├── .cargo └── config.toml ├── .circleci └── config.yml ├── .github ├── FUNDING.yml └── workflows │ ├── build_push.yml │ ├── no-response.yml │ └── publish_release.yml ├── .gitignore ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── LICENSE-APACHE.md ├── LICENSE.md ├── README.md ├── app ├── Cargo.lock ├── Cargo.toml ├── benches │ ├── geometry │ │ └── main.rs │ ├── rdp │ │ └── main.rs │ ├── yuv16 │ │ └── main.rs │ └── yuv8 │ │ └── main.rs └── src │ ├── main.rs │ ├── max_divergence.rs │ └── support.rs ├── assets ├── bench.jpg └── main_test.jpg ├── coeffs ├── Cargo.toml └── src │ └── main.rs ├── fuzz ├── .gitignore ├── Cargo.toml ├── fuzz_avx512.sh ├── gbr_to_rgb │ └── gbr_to_rgb.rs ├── rdp │ └── rdp.rs ├── rgb16_to_nv16 │ └── rgb16_to_nv16.rs ├── rgb16_to_yuv16 │ └── rgb16_to_yuv16.rs ├── rgb_to_f16 │ └── rgb_to_f16.rs ├── rgb_to_nv │ └── rgb_to_nv.rs ├── rgb_to_y │ └── rgb_to_y.rs ├── rgb_to_yuv │ └── rgb_to_yuv.rs ├── shuffle │ └── shuffle.rs ├── y16_to_rgb16 │ └── y16_to_rgb16.rs ├── y_to_rgb │ └── y_to_rgb.rs ├── yuv16_to_ar30 │ └── yuv16_to_ar30.rs ├── yuv16_to_rgb16 │ └── yuv16_to_rgb16.rs ├── yuv16_to_rgb_f16 │ └── yuv16_to_rgb_f16.rs ├── yuv_nv10_to_rgb │ └── yuv_nv10_to_rgb.rs ├── yuv_nv16_to_rgb16 │ └── yuv_nv16_to_rgb16.rs ├── yuv_nv_to_rgb │ └── yuv_nv_to_rgb.rs ├── yuv_to_rgb │ └── yuv_to_rgb.rs └── yuv_to_yuyu2 │ └── yuv_to_yuyu2.rs ├── rust-toolchain.toml ├── src ├── ar30_rgb.rs ├── avx2 │ ├── avx2_utils.rs │ ├── ayuv_to_rgba.rs │ ├── f16_converter.rs │ ├── gbr_to_rgb.rs │ ├── mod.rs │ ├── rdp_to_yuv.rs │ ├── rgb_to_nv.rs │ ├── rgb_to_nv420.rs │ ├── rgb_to_nv420_prof.rs │ ├── rgb_to_nv_prof.rs │ ├── rgb_to_y.rs │ ├── rgb_to_yuv420_prof.rs │ ├── rgb_to_yuv_p16.rs │ ├── rgb_to_yuv_p16_420.rs │ ├── rgb_to_yuv_p16_420_d16.rs │ ├── rgb_to_yuv_p16_d16.rs │ ├── rgb_to_yuv_prof.rs │ ├── rgba_to_nv_fast.rs │ ├── rgba_to_nv_fast420.rs │ ├── rgba_to_yuv.rs │ ├── rgba_to_yuv420.rs │ ├── rgba_to_yuv_fast.rs │ ├── rgba_to_yuv_fast420.rs │ ├── shuffle.rs │ ├── y_to_rgba.rs │ ├── y_to_rgba_alpha.rs │ ├── yuv_nv_to_rgba.rs │ ├── yuv_nv_to_rgba420.rs │ ├── yuv_nv_to_rgba420_prof.rs │ ├── yuv_nv_to_rgba422.rs │ ├── yuv_nv_to_rgba_fast.rs │ ├── yuv_nv_to_rgba_fast420.rs │ ├── yuv_nv_to_rgba_prof.rs │ ├── yuv_p16_to_rgb16.rs │ ├── yuv_p16_to_rgb16_alpha.rs │ ├── yuv_p16_to_rgb8.rs │ ├── yuv_p16_to_rgb8_alpha.rs │ ├── yuv_p16_to_rgb_d16.rs │ ├── yuv_p16_to_rgb_f16.rs │ ├── yuv_to_rgba.rs │ ├── yuv_to_rgba420.rs │ ├── yuv_to_rgba422.rs │ ├── yuv_to_rgba_alpha.rs │ ├── yuv_to_yuv2.rs │ ├── yuva_p16_to_rgb_f16.rs │ ├── yuy2_to_rgb.rs │ └── yuy2_to_yuv.rs ├── avx512bw │ ├── avx512_setr.rs │ ├── avx512_utils.rs │ ├── mod.rs │ ├── rgb_to_nv420.rs │ ├── rgb_to_nv420_prof.rs │ ├── rgb_to_y.rs │ ├── rgb_to_yuv_p16.rs │ ├── rgb_to_yuv_p16_420.rs │ ├── rgba_to_yuv.rs │ ├── rgba_to_yuv420.rs │ ├── rgba_to_yuv_fast.rs │ ├── rgba_to_yuv_fast420.rs │ ├── y_to_rgb.rs │ ├── yuv_nv_to_rgba.rs │ ├── yuv_nv_to_rgba420.rs │ ├── yuv_nv_to_rgba422.rs │ ├── yuv_nv_to_rgba_fast420.rs │ ├── yuv_p16_to_rgb16.rs │ ├── yuv_p16_to_rgb8.rs │ ├── yuv_to_rgba.rs │ ├── yuv_to_rgba420.rs │ ├── yuv_to_rgba422.rs │ └── yuv_to_rgba_alpha.rs ├── ayuv_to_rgb.rs ├── built_coefficients.rs ├── f16_ar30.rs ├── f16_converter.rs ├── from_identity.rs ├── from_identity_alpha.rs ├── from_identity_alpha_f16.rs ├── from_identity_f16.rs ├── geometry.rs ├── images.rs ├── internals.rs ├── lib.rs ├── mirroring.rs ├── neon │ ├── ar30_utils.rs │ ├── ayuv_to_rgba.rs │ ├── f16_converter.rs │ ├── f16_utils.rs │ ├── gbr_to_rgb.rs │ ├── mod.rs │ ├── rgb_to_nv420_prof.rs │ ├── rgb_to_nv_prof.rs │ ├── rgb_to_y.rs │ ├── rgb_to_yuv420_prof.rs │ ├── rgb_to_yuv_p16.rs │ ├── rgb_to_yuv_p16_420.rs │ ├── rgb_to_yuv_prof.rs │ ├── rgba_to_nv.rs │ ├── rgba_to_nv420.rs │ ├── rgba_to_nv_dot.rs │ ├── rgba_to_nv_dot420.rs │ ├── rgba_to_yuv.rs │ ├── rgba_to_yuv420.rs │ ├── rgba_to_yuv_dot.rs │ ├── rgba_to_yuv_dot420.rs │ ├── rgbx_to_nv_fast.rs │ ├── rgbx_to_nv_fast420.rs │ ├── rgbx_to_yuv_fast.rs │ ├── rgbx_to_yuv_fast420.rs │ ├── shuffle.rs │ ├── utils.rs │ ├── y_p16_to_rgba16.rs │ ├── y_to_rgb.rs │ ├── y_to_rgb_alpha.rs │ ├── ycgco_to_rgb.rs │ ├── yuv_nv_p10_to_ar30.rs │ ├── yuv_nv_p10_to_rgba.rs │ ├── yuv_nv_p10_to_rgba_prof.rs │ ├── yuv_nv_p16_to_rgb.rs │ ├── yuv_nv_to_rgba.rs │ ├── yuv_nv_to_rgba420.rs │ ├── yuv_nv_to_rgba420_prof.rs │ ├── yuv_nv_to_rgba_prof.rs │ ├── yuv_nv_to_rgbx_fast.rs │ ├── yuv_nv_to_rgbx_fast420.rs │ ├── yuv_p16_to_rgba16.rs │ ├── yuv_p16_to_rgba16_alpha.rs │ ├── yuv_p16_to_rgba8.rs │ ├── yuv_p16_to_rgba_alpha.rs │ ├── yuv_p16_to_rgba_f16.rs │ ├── yuv_to_rgba.rs │ ├── yuv_to_rgba420.rs │ ├── yuv_to_rgba_alpha.rs │ ├── yuv_to_yuy2.rs │ ├── yuva_p16_to_rgba_f16.rs │ ├── yuy2_to_rgb.rs │ └── yuy2_to_yuv.rs ├── numerics.rs ├── rdp.rs ├── rgb16_to_yuv_p16.rs ├── rgb_ar30.rs ├── rgb_to_nv_p16.rs ├── rgb_to_y.rs ├── rgb_to_ycgco.rs ├── rgb_to_ycgco_r.rs ├── rgba_to_nv.rs ├── rgba_to_yuv.rs ├── sharpyuv │ ├── mod.rs │ ├── sharp_gamma.rs │ └── sharp_rgba_to_yuv.rs ├── shuffle.rs ├── sse │ ├── gbr_to_rgb.rs │ ├── mod.rs │ ├── rgb_to_nv.rs │ ├── rgb_to_nv420.rs │ ├── rgb_to_nv420_prof.rs │ ├── rgb_to_nv_prof.rs │ ├── rgb_to_y.rs │ ├── rgb_to_yuv420_prof.rs │ ├── rgb_to_yuv_p16.rs │ ├── rgb_to_yuv_p16_420.rs │ ├── rgb_to_yuv_prof.rs │ ├── rgba_to_nv_fast.rs │ ├── rgba_to_nv_fast420.rs │ ├── rgba_to_yuv.rs │ ├── rgba_to_yuv420.rs │ ├── rgba_to_yuv_fast.rs │ ├── rgba_to_yuv_fast420.rs │ ├── shuffle.rs │ ├── utils.rs │ ├── y_to_rgba.rs │ ├── y_to_rgba_alpha.rs │ ├── yuv_nv_p16_to_rgb.rs │ ├── yuv_nv_to_rgba.rs │ ├── yuv_nv_to_rgba420.rs │ ├── yuv_nv_to_rgba420_prof.rs │ ├── yuv_nv_to_rgba422.rs │ ├── yuv_nv_to_rgba_fast.rs │ ├── yuv_nv_to_rgba_fast420.rs │ ├── yuv_nv_to_rgba_prof.rs │ ├── yuv_p16_to_rgb16.rs │ ├── yuv_p16_to_rgb16_alpha.rs │ ├── yuv_p16_to_rgb8.rs │ ├── yuv_p16_to_rgb8_alpha.rs │ ├── yuv_to_rgba.rs │ ├── yuv_to_rgba420.rs │ ├── yuv_to_rgba422.rs │ ├── yuv_to_rgba_alpha.rs │ ├── yuv_to_yuy2.rs │ ├── yuy2_to_rgb.rs │ └── yuy2_to_yuv.rs ├── to_identity.rs ├── wasm32 │ ├── mod.rs │ ├── transpose.rs │ ├── utils.rs │ ├── y_to_rgb.rs │ ├── yuv_nv_to_rgba.rs │ ├── yuv_nv_to_rgba420.rs │ ├── yuv_to_rgba.rs │ └── yuv_to_rgba420.rs ├── y_p16_to_rgb16.rs ├── y_p16_with_alpha_to_rgb16.rs ├── y_to_rgb.rs ├── y_with_alpha_to_rgb.rs ├── ycgco_re_to_rgb.rs ├── ycgco_re_to_rgb_alpha.rs ├── ycgco_to_rgb.rs ├── ycgco_to_rgb_alpha.rs ├── ycgcor_support.rs ├── yuv_error.rs ├── yuv_nv_p10_to_ar30.rs ├── yuv_nv_p10_to_rgb.rs ├── yuv_nv_p16_to_rgb16.rs ├── yuv_nv_to_rgba.rs ├── yuv_p10_rgba.rs ├── yuv_p16_ar30.rs ├── yuv_p16_rgba16_alpha.rs ├── yuv_p16_rgba_alpha.rs ├── yuv_p16_rgba_f16.rs ├── yuv_p16_rgba_p16.rs ├── yuv_support.rs ├── yuv_to_rgba.rs ├── yuv_to_rgba_alpha.rs ├── yuv_to_yuy2.rs ├── yuv_to_yuy2_p16.rs ├── yuva_p16_rgba_f16.rs ├── yuy2_to_rgb.rs ├── yuy2_to_rgb_p16.rs ├── yuy2_to_yuv.rs └── yuy2_to_yuv_p16.rs └── wasm ├── .gitignore ├── Cargo.toml ├── run.sh └── src └── lib.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.x86_64-pc-windows-msvc] 2 | rustflags = ["-Ctarget-cpu=native"] 3 | 4 | [target.wasm32-unknown-unknown] 5 | rustflags = ["-C", "target-feature=+simd128"] 6 | 7 | [target.x86_64-unknown-linux-gnu] 8 | rustflags = ["-C", "link-arg=-fuse-ld=lld"] -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | jobs: 4 | build: 5 | docker: 6 | - image: cimg/rust:1.82.0 7 | steps: 8 | - checkout 9 | - run: 10 | name: CPU Info 11 | command: "cat /proc/cpuinfo" 12 | - restore_cache: 13 | key: cargo-{{ checksum "Cargo.lock" }} 14 | - run: cargo install cargo-fuzz 15 | - run: 16 | name: Run Tests No Features 17 | command: "cargo test --no-default-features" 18 | - run: 19 | name: Run Tests Featured AVX-512 20 | command: "cargo test --no-default-features --features nightly_avx512" 21 | # - run: 22 | # no_output_timeout: 20m 23 | # command: cargo fuzz run rgb_to_yuv --no-default-features --features nightly_avx512 -- -max_total_time=15 24 | # - run: cargo fuzz run rgb_to_nv --no-default-features --features nightly_avx512 -- -max_total_time=15 25 | # - run: cargo fuzz run rgb_to_y --no-default-features --features nightly_avx512 -- -max_total_time=15 26 | # - run: cargo fuzz run rgb16_to_yuv16 --no-default-features --features nightly_avx512 -- -max_total_time=15 27 | # - run: cargo fuzz run rgb16_to_nv16 --no-default-features --features nightly_avx512 -- -max_total_time=15 28 | # - run: cargo fuzz run yuv_to_rgb --no-default-features --features nightly_avx512 -- -max_total_time=15 29 | # - run: cargo fuzz run yuv_nv_to_rgb --no-default-features --features nightly_avx512 -- -max_total_time=15 30 | # - run: cargo fuzz run y_to_rgb --no-default-features --features nightly_avx512 -- -max_total_time=15 31 | # - run: cargo fuzz run yuv16_to_rgb16 --no-default-features --features nightly_avx512 -- -max_total_time=15 32 | # - run: cargo fuzz run y16_to_rgb16 --no-default-features --features nightly_avx512 -- -max_total_time=15 33 | # - run: cargo fuzz run yuv_to_yuyu2 --no-default-features --features nightly_avx512 -- -max_total_time=15 34 | # - run: cargo fuzz run yuv_nv16_to_rgb16 --no-default-features --features nightly_avx512 -- -max_total_time=15 35 | # - run: cargo fuzz run shuffle --no-default-features --features nightly_avx512 -- -max_total_time=15 36 | # - run: cargo fuzz run rgb_to_f16 --no-default-features --features nightly_avx512 -- -max_total_time=15 37 | - save_cache: 38 | key: cargo-{{ checksum "Cargo.lock" }} 39 | paths: 40 | - ~/.cargo -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: awxkee 4 | -------------------------------------------------------------------------------- /.github/workflows/no-response.yml: -------------------------------------------------------------------------------- 1 | name: no-response 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' # Runs daily at midnight 6 | workflow_dispatch: 7 | 8 | jobs: 9 | noResponse: 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/stale@v9 16 | with: 17 | repo-token: ${{ github.token }} 18 | days-before-stale: -1 19 | days-before-close: 14 20 | only-labels: 'waiting for author' 21 | stale-issue-label: 'waiting for author' 22 | stale-pr-label: 'waiting for author' 23 | remove-stale-when-updated: true 24 | ignore-updates: false 25 | close-issue-message: This issue has been automatically closed due to inactivity. We requested additional information but have not received a response from the original author. Without the requested details, we cannot proceed. If you have or find the information needed, please comment so we can reopen the issue. 26 | close-pr-message: This pull request has been automatically closed due to inactivity. We requested additional information but have not received a response from the original author. Without the requested details, we cannot proceed. If you have the needed information or updates, please reopen the PR or comment so we can continue the review. -------------------------------------------------------------------------------- /.github/workflows/publish_release.yml: -------------------------------------------------------------------------------- 1 | name: Create Release 2 | 3 | concurrency: 4 | group: ${{ github.workflow }}-${{ github.ref }} 5 | cancel-in-progress: true 6 | 7 | on: 8 | push: 9 | tags: 10 | - '*' 11 | 12 | jobs: 13 | build_and_publish: 14 | name: Build 15 | runs-on: ubuntu-latest 16 | environment: Cargo 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: actions-rust-lang/setup-rust-toolchain@v1 20 | - name: Make a release 21 | env: 22 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_TOKEN }} 23 | run: cargo publish --manifest-path Cargo.toml -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | app/target 4 | Cargo.lock -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Added conversions -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | radzivon.bartoshyk@proton.me. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | workspace = { members = ["app", "fuzz", "coeffs"] } 2 | 3 | [package] 4 | name = "yuv" 5 | version = "0.8.4" 6 | edition = "2021" 7 | description = "High performance utilities for YUV format handling and conversion." 8 | readme = "README.md" 9 | keywords = ["yuv", "ycbcr", "yuv2rgb", "rgb2yuv", "converter"] 10 | license = "BSD-3-Clause OR Apache-2.0" 11 | authors = ["Radzivon Bartoshyk"] 12 | documentation = "https://github.com/awxkee/yuvutils-rs" 13 | categories = ["multimedia::images", "multimedia::video"] 14 | homepage = "https://github.com/awxkee/yuvutils-rs" 15 | repository = "https://github.com/awxkee/yuvutils-rs" 16 | exclude = ["*.jpg", "assets/*", "*.png", "assets/bench.jpg", "assets/bench.png", "*.yuv2"] 17 | rust-version = "1.82.0" 18 | 19 | [dependencies] 20 | num-traits = "0.2.19" 21 | rayon = { version = "1.10", optional = true } 22 | fast_transpose = { version = "0.2", optional = true } 23 | 24 | [dev-dependencies] 25 | rand = "0.9.0" 26 | 27 | [features] 28 | default = ["avx", "sse", "rdm"] 29 | # On x86 architectures runtime dispatch is used to detect if AVX, SSE is available 30 | # disable those features only for testing or reducing binary size, if you're sure that your hardware 31 | # do not support it or already shadowed by another feature. 32 | # 33 | # It is safe to enable any features because all features availability will be checked at runtime. 34 | # 35 | # Enables AVX2 support 36 | avx = [] 37 | # Enables SSE4.1 support 38 | sse = [] 39 | # RDM corresponds FEAT_RDM on ARM 40 | rdm = [] 41 | # Turning on `f16` support, nightly compiler is required 42 | nightly_f16 = [] 43 | # Enables AVX-512, support, nightly compiler is required 44 | nightly_avx512 = ["fast_transpose/nightly_avx512"] 45 | # Enables FEAT_I8MM on ARM 46 | nightly_i8mm = [] 47 | # Enables `fast_mode` support on available paths 48 | fast_mode = [] 49 | # Enables `professional_mode` support on available paths 50 | professional_mode = [] 51 | # Enables `rayon` support, use with care, in common, YUV encoding/decoding is more usually expected to be used in single thread mode 52 | rayon = ["dep:rayon"] 53 | # Support for Big-Endian YUV 54 | big_endian = [] 55 | # Enables Mirroring and Rotating methods 56 | geometry = ["dep:fast_transpose"] 57 | # Enables RemoteFX Conversion 58 | rdp = [] 59 | # Enables YCgCo-Re/YCgCo-Ro support 60 | ycgco_r_type = [] 61 | 62 | [package.metadata.docs.rs] 63 | # To build locally: 64 | # RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps --open 65 | all-features = true 66 | rustdoc-args = ["--cfg", "docsrs"] 67 | 68 | [profile.dev.package] 69 | miniz_oxide.opt-level = 3 70 | png.opt-level = 3 71 | flate2.opt-level = 3 72 | image.opt-level = 3 73 | 74 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Radzivon Bartoshyk. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, 4 | are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | 3. Neither the name of the copyright holder nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 21 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 24 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /app/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "app" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /app/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | yuv = { path = "..", features = ["nightly_f16", "fast_mode", "sse", "avx", "professional_mode", "nightly_avx512", "rdp", "ycgco_r_type", "nightly_i8mm"], default-features = false } 8 | image = { version = "0.25.5", default-features = false, features = ["png", "jpeg"] } 9 | yuv-sys = "0.3.7" 10 | rand = "0.9.0" 11 | bytemuck = "1.23.0" 12 | 13 | [features] 14 | nightly_avx512 = ["yuv/nightly_avx512"] 15 | nightly_i8mm = ["yuv/nightly_i8mm"] 16 | fast_mode = ["yuv/fast_mode"] 17 | rdm = ["yuv/rdm"] 18 | professional_mode = ["yuv/professional_mode"] 19 | 20 | [dev-dependencies] 21 | criterion = "0.6" 22 | 23 | [[bench]] 24 | name = "yuv8" 25 | harness = false 26 | 27 | [[bench]] 28 | name = "yuv16" 29 | harness = false 30 | 31 | [[bench]] 32 | name = "geometry" 33 | harness = false 34 | 35 | [[bench]] 36 | name = "rdp" 37 | harness = false 38 | -------------------------------------------------------------------------------- /app/src/main.rs: -------------------------------------------------------------------------------- 1 | #![feature(f16)] 2 | /* 3 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of the copyright holder nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | mod support; 31 | 32 | use image::{ColorType, DynamicImage, EncodableLayout, GenericImageView, ImageReader}; 33 | use std::fs::File; 34 | use std::io::Read; 35 | use std::time::Instant; 36 | use yuv::{ 37 | i010_alpha_to_rgba10, i010_to_rgba10, icgc_re010_to_rgba, icgc_ro010_to_rgba, 38 | icgc_ro210_to_rgba, icgc_ro410_to_rgba, rgba10_to_i010, rgba12_to_i412, rgba_to_icgc_re010, 39 | rgba_to_icgc_ro010, rgba_to_icgc_ro210, rgba_to_icgc_ro410, rgba_to_ycgco420, rgba_to_ycgco444, 40 | rgba_to_yuv420, rgba_to_yuv422, rgba_to_yuv444, rgba_to_yuv_nv12, rgba_to_yuv_nv16, 41 | rgba_to_yuv_nv24, ycgco420_to_rgba, ycgco444_to_rgba, yuv420_alpha_to_rgba, yuv420_to_rgba, 42 | yuv422_to_rgba, yuv444_to_rgba, yuv_nv12_to_rgba, yuv_nv16_to_rgba, yuv_nv24_to_rgba, 43 | YuvBiPlanarImageMut, YuvChromaSubsampling, YuvConversionMode, YuvPlanarImageMut, 44 | YuvPlanarImageWithAlpha, YuvRange, YuvStandardMatrix, 45 | }; 46 | 47 | fn read_file_bytes(file_path: &str) -> Result, String> { 48 | // Open the file 49 | let mut file = File::open(file_path).unwrap(); 50 | 51 | // Create a buffer to hold the file contents 52 | let mut buffer = Vec::new(); 53 | 54 | // Read the file contents into the buffer 55 | file.read_to_end(&mut buffer).unwrap(); 56 | 57 | // Return the buffer 58 | Ok(buffer) 59 | } 60 | use core::f16; 61 | 62 | fn main() { 63 | let mut img = ImageReader::open("./assets/bench.png") 64 | .unwrap() 65 | .decode() 66 | .unwrap(); 67 | let img = DynamicImage::ImageRgba8(img.to_rgba8()); 68 | 69 | let dimensions = img.dimensions(); 70 | 71 | let width = dimensions.0; 72 | let height = dimensions.1; 73 | 74 | let src_bytes = img.as_bytes(); 75 | let mut components = match img.color() { 76 | ColorType::Rgb8 => 3, 77 | ColorType::Rgba8 => 4, 78 | _ => { 79 | panic!("Not accepted") 80 | } 81 | }; 82 | 83 | let y_stride = width as usize + 100; 84 | let u_stride = (width + 1) / 2 + 100; 85 | let v_stride = (width + 1) / 2 + 100; 86 | let mut y_plane = vec![0u8; y_stride as usize * height as usize]; 87 | let mut u_plane = vec![0u8; height as usize * u_stride as usize]; 88 | let mut v_plane = vec![0u8; height as usize * v_stride as usize]; 89 | 90 | let rgba_stride = width as usize * components; 91 | let mut rgba = vec![0u8; height as usize * rgba_stride]; 92 | 93 | let start_time = Instant::now(); 94 | 95 | let mut y_nv_plane = vec![0u8; width as usize * height as usize]; 96 | let mut uv_nv_plane = vec![0u8; width as usize * (height as usize + 1) / 2]; 97 | 98 | let mut planar_image = 99 | YuvBiPlanarImageMut::::alloc(width as u32, height as u32, YuvChromaSubsampling::Yuv444); 100 | // let mut bytes_16: Vec = src_bytes 101 | // .iter() 102 | // .map(|&x| ((x as u16) << 2) | ((x as u16) >> 6)) 103 | // .collect(); 104 | 105 | let start_time = Instant::now(); 106 | 107 | rgba_to_yuv_nv24( 108 | &mut planar_image, 109 | &src_bytes, 110 | rgba_stride as u32, 111 | YuvRange::Limited, 112 | YuvStandardMatrix::Bt709, 113 | YuvConversionMode::Professional, 114 | ) 115 | .unwrap(); 116 | 117 | println!("Forward time: {:?}", start_time.elapsed()); 118 | let fixed = planar_image.to_fixed(); 119 | rgba.fill(255); 120 | 121 | // let a_plane = vec![1023; height as usize * width as usize]; 122 | // 123 | // let alpha = YuvPlanarImageWithAlpha { 124 | // y_plane: planar_image.y_plane.borrow(), 125 | // y_stride: planar_image.y_stride, 126 | // u_plane: planar_image.u_plane.borrow(), 127 | // u_stride: planar_image.u_stride, 128 | // v_plane: planar_image.v_plane.borrow(), 129 | // v_stride: planar_image.v_stride, 130 | // a_plane: &a_plane, 131 | // a_stride: width as u32, 132 | // width, 133 | // height, 134 | // }; 135 | 136 | yuv_nv24_to_rgba( 137 | &fixed, 138 | &mut rgba, 139 | rgba_stride as u32, 140 | YuvRange::Limited, 141 | YuvStandardMatrix::Bt709, 142 | YuvConversionMode::Balanced, 143 | ) 144 | .unwrap(); 145 | 146 | // 147 | // let fixed_biplanar = bi_planar_image.to_fixed(); 148 | let fixed_planar = planar_image.to_fixed(); 149 | // // bytes_16.fill(0); 150 | // 151 | // let mut j_rgba = vec![0u8; dimensions.0 as usize * dimensions.1 as usize * 4]; 152 | 153 | // // 154 | // i210_to_rgb_f16( 155 | // &fixed_planar, 156 | // &mut rgba_f16, 157 | // rgba_stride as u32, 158 | // YuvRange::Limited, 159 | // YuvStandardMatrix::Bt709, 160 | // ) 161 | // .unwrap(); 162 | // // 163 | // println!("Backward time: {:?}", start_time.elapsed()); 164 | // 165 | // rgba.fill(0); 166 | // 167 | // // convert_rgb_f16_to_rgb(&rgba_f16, rgba_stride, &mut rgba, rgba_stride, width as usize, height as usize).unwrap(); 168 | // 169 | 170 | // rgba = bytes_16.iter().map(|&x| (x >> 2) as u8).collect(); 171 | 172 | // rgba = rgba_f16.iter().map(|&x| (x as f32 * 255.) as u8).collect(); 173 | 174 | image::save_buffer( 175 | "converted_sharp151.png", 176 | rgba.as_bytes(), 177 | dimensions.0, 178 | dimensions.1, 179 | if components == 3 { 180 | image::ExtendedColorType::Rgb8 181 | } else { 182 | image::ExtendedColorType::Rgba8 183 | }, 184 | ) 185 | .unwrap(); 186 | } 187 | -------------------------------------------------------------------------------- /app/src/support.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use std::fs::File; 30 | use std::io::{Error, Read, Write}; 31 | use std::path::Path; 32 | use yuv::{BufferStoreMut, YuvPlanarImageMut}; 33 | 34 | pub(crate) fn save_yuy2_image( 35 | filename: &str, 36 | width: usize, 37 | height: usize, 38 | yuy2_data: &[u8], 39 | ) -> std::io::Result<()> { 40 | let mut file = File::create(filename)?; 41 | file.write_all(yuy2_data)?; 42 | Ok(()) 43 | } 44 | 45 | pub fn read_yuv420_16bit>( 46 | path: P, 47 | width: usize, 48 | height: usize, 49 | ) -> Result, Error> { 50 | let mut file = File::open(path)?; 51 | let frame_size = width * height; 52 | let chroma_size = (width / 2) * (height / 2); 53 | 54 | let mut y_buf = vec![0u8; frame_size * 2]; 55 | let mut u_buf = vec![0u8; chroma_size * 2]; 56 | let mut v_buf = vec![0u8; chroma_size * 2]; 57 | 58 | file.read_exact(&mut y_buf)?; 59 | file.read_exact(&mut u_buf)?; 60 | file.read_exact(&mut v_buf)?; 61 | 62 | let y = y_buf 63 | .chunks_exact(2) 64 | .map(|b| u16::from_le_bytes([b[0], b[1]])) 65 | .collect::>(); 66 | 67 | let u = u_buf 68 | .chunks_exact(2) 69 | .map(|b| u16::from_le_bytes([b[0], b[1]])) 70 | .collect::>(); 71 | 72 | let v = v_buf 73 | .chunks_exact(2) 74 | .map(|b| u16::from_le_bytes([b[0], b[1]])) 75 | .collect::>(); 76 | 77 | Ok(YuvPlanarImageMut { 78 | y_plane: BufferStoreMut::Owned(y), 79 | y_stride: width as u32, 80 | u_plane: BufferStoreMut::Owned(u), 81 | u_stride: (width as u32).div_ceil(2), 82 | v_plane: BufferStoreMut::Owned(v), 83 | v_stride: (width as u32).div_ceil(2), 84 | width: width as u32, 85 | height: height as u32, 86 | }) 87 | } 88 | -------------------------------------------------------------------------------- /assets/bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awxkee/yuvutils-rs/f7e469d84cd5cc3af7ebacd1e2626d333c8e50bf/assets/bench.jpg -------------------------------------------------------------------------------- /assets/main_test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awxkee/yuvutils-rs/f7e469d84cd5cc3af7ebacd1e2626d333c8e50bf/assets/main_test.jpg -------------------------------------------------------------------------------- /coeffs/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "coeffs" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | rug = "1.24.1" -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "app-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | arbitrary = "1.4.1" 12 | libfuzzer-sys = "0.4" 13 | yuv = { path = "..", features = ["nightly_f16", "fast_mode", "professional_mode", "rdp"], default-features = false } 14 | 15 | [features] 16 | default = [] 17 | avx = ["yuv/avx"] 18 | sse = ["yuv/sse"] 19 | rdm = ["yuv/rdm"] 20 | nightly_avx512 = ["yuv/nightly_avx512"] 21 | nightly_i8mm = ["yuv/nightly_i8mm"] 22 | 23 | [[bin]] 24 | name = "yuv_to_rgb" 25 | path = "yuv_to_rgb/yuv_to_rgb.rs" 26 | test = false 27 | doc = false 28 | bench = false 29 | 30 | [[bin]] 31 | name = "gbr_to_rgb" 32 | path = "gbr_to_rgb/gbr_to_rgb.rs" 33 | test = false 34 | doc = false 35 | bench = false 36 | 37 | [[bin]] 38 | name = "yuv_nv_to_rgb" 39 | path = "yuv_nv_to_rgb/yuv_nv_to_rgb.rs" 40 | test = false 41 | doc = false 42 | bench = false 43 | 44 | [[bin]] 45 | name = "yuv_nv16_to_rgb16" 46 | path = "yuv_nv16_to_rgb16/yuv_nv16_to_rgb16.rs" 47 | test = false 48 | doc = false 49 | bench = false 50 | 51 | [[bin]] 52 | name = "yuv_nv10_to_rgb" 53 | path = "yuv_nv10_to_rgb/yuv_nv10_to_rgb.rs" 54 | test = false 55 | doc = false 56 | bench = false 57 | 58 | [[bin]] 59 | name = "y_to_rgb" 60 | path = "y_to_rgb/y_to_rgb.rs" 61 | test = false 62 | doc = false 63 | bench = false 64 | 65 | [[bin]] 66 | name = "yuv16_to_rgb16" 67 | path = "yuv16_to_rgb16/yuv16_to_rgb16.rs" 68 | test = false 69 | doc = false 70 | bench = false 71 | 72 | [[bin]] 73 | name = "yuv16_to_rgb_f16" 74 | path = "yuv16_to_rgb_f16/yuv16_to_rgb_f16.rs" 75 | test = false 76 | doc = false 77 | bench = false 78 | 79 | [[bin]] 80 | name = "yuv16_to_ar30" 81 | path = "yuv16_to_ar30/yuv16_to_ar30.rs" 82 | test = false 83 | doc = false 84 | bench = false 85 | 86 | [[bin]] 87 | name = "y16_to_rgb16" 88 | path = "y16_to_rgb16/y16_to_rgb16.rs" 89 | test = false 90 | doc = false 91 | bench = false 92 | 93 | [[bin]] 94 | name = "yuv_to_yuyu2" 95 | path = "yuv_to_yuyu2/yuv_to_yuyu2.rs" 96 | test = false 97 | doc = false 98 | bench = false 99 | 100 | [[bin]] 101 | name = "rgb_to_yuv" 102 | path = "rgb_to_yuv/rgb_to_yuv.rs" 103 | test = false 104 | doc = false 105 | bench = false 106 | 107 | [[bin]] 108 | name = "rdp" 109 | path = "rdp/rdp.rs" 110 | test = false 111 | doc = false 112 | bench = false 113 | 114 | [[bin]] 115 | name = "rgb16_to_yuv16" 116 | path = "rgb16_to_yuv16/rgb16_to_yuv16.rs" 117 | test = false 118 | doc = false 119 | bench = false 120 | 121 | [[bin]] 122 | name = "rgb_to_y" 123 | path = "rgb_to_y/rgb_to_y.rs" 124 | test = false 125 | doc = false 126 | bench = false 127 | 128 | [[bin]] 129 | name = "rgb_to_nv" 130 | path = "rgb_to_nv/rgb_to_nv.rs" 131 | test = false 132 | doc = false 133 | bench = false 134 | 135 | [[bin]] 136 | name = "rgb16_to_nv16" 137 | path = "rgb16_to_nv16/rgb16_to_nv16.rs" 138 | test = false 139 | doc = false 140 | bench = false 141 | 142 | [[bin]] 143 | name = "shuffle" 144 | path = "shuffle/shuffle.rs" 145 | test = false 146 | doc = false 147 | bench = false 148 | 149 | [[bin]] 150 | name = "rgb_to_f16" 151 | path = "rgb_to_f16/rgb_to_f16.rs" 152 | test = false 153 | doc = false 154 | bench = false 155 | -------------------------------------------------------------------------------- /fuzz/fuzz_avx512.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | cargo fuzz run rgb_to_yuv --no-default-features --features nightly_avx512 -- -max_total_time=8 4 | cargo fuzz run rgb_to_nv --no-default-features --features nightly_avx512 -- -max_total_time=8 5 | cargo fuzz run rgb_to_y --no-default-features --features nightly_avx512 -- -max_total_time=8 6 | cargo fuzz run rgb16_to_yuv16 --no-default-features --features nightly_avx512 -- -max_total_time=8 7 | cargo fuzz run rgb16_to_nv16 --no-default-features --features nightly_avx512 -- -max_total_time=8 8 | cargo fuzz run yuv_to_rgb --no-default-features --features nightly_avx512 -- -max_total_time=8 9 | cargo fuzz run yuv_nv_to_rgb --no-default-features --features nightly_avx512 -- -max_total_time=8 10 | cargo fuzz run y_to_rgb --no-default-features --features nightly_avx512 -- -max_total_time=8 11 | cargo fuzz run yuv16_to_rgb16 --no-default-features --features nightly_avx512 -- -max_total_time=8 12 | cargo fuzz run y16_to_rgb16 --no-default-features --features nightly_avx512 -- -max_total_time=8 13 | cargo fuzz run yuv_to_yuyu2 --no-default-features --features nightly_avx512 -- -max_total_time=8 14 | cargo fuzz run yuv_nv16_to_rgb16 --no-default-features --features nightly_avx512 -- -max_total_time=8 15 | cargo fuzz run shuffle --no-default-features --features nightly_avx512 -- -max_total_time=8 16 | cargo fuzz run rgb_to_f16 --no-default-features --features nightly_avx512 -- -max_total_time=8 -------------------------------------------------------------------------------- /fuzz/gbr_to_rgb/gbr_to_rgb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | gb10_alpha_to_rgba10, gb10_to_rgb10, gb10_to_rgba10, gbr_to_rgb, gbr_to_rgba, 35 | gbr_with_alpha_to_rgba, YuvPlanarImage, YuvPlanarImageWithAlpha, YuvRange, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8, u8)| { 39 | fuzz_yuv_444(data.0, data.1, data.2, data.3, data.4); 40 | }); 41 | 42 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, u_value: u8, v_value: u8) { 43 | if i_height == 0 || i_width == 0 { 44 | return; 45 | } 46 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 47 | let a_plane = vec![y_value; i_height as usize * i_width as usize]; 48 | let u_plane = vec![u_value; i_width as usize * i_height as usize]; 49 | let v_plane = vec![v_value; i_width as usize * i_height as usize]; 50 | 51 | let planar_image = YuvPlanarImage { 52 | y_plane: &y_plane, 53 | y_stride: i_width as u32, 54 | u_plane: &u_plane, 55 | u_stride: i_width as u32, 56 | v_plane: &v_plane, 57 | v_stride: i_width as u32, 58 | width: i_width as u32, 59 | height: i_height as u32, 60 | }; 61 | 62 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 63 | 64 | gbr_to_rgb( 65 | &planar_image, 66 | &mut target_rgb, 67 | i_width as u32 * 3, 68 | YuvRange::Limited, 69 | ) 70 | .unwrap(); 71 | 72 | gbr_to_rgb( 73 | &planar_image, 74 | &mut target_rgb, 75 | i_width as u32 * 3, 76 | YuvRange::Full, 77 | ) 78 | .unwrap(); 79 | 80 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 81 | 82 | gbr_to_rgba( 83 | &planar_image, 84 | &mut target_rgba, 85 | i_width as u32 * 4, 86 | YuvRange::Limited, 87 | ) 88 | .unwrap(); 89 | 90 | gbr_to_rgba( 91 | &planar_image, 92 | &mut target_rgba, 93 | i_width as u32 * 4, 94 | YuvRange::Full, 95 | ) 96 | .unwrap(); 97 | 98 | let planar_image_with_alpha = YuvPlanarImageWithAlpha { 99 | y_plane: &y_plane, 100 | y_stride: i_width as u32, 101 | u_plane: &u_plane, 102 | u_stride: i_width as u32, 103 | v_plane: &v_plane, 104 | v_stride: i_width as u32, 105 | a_plane: &a_plane, 106 | a_stride: i_width as u32, 107 | width: i_width as u32, 108 | height: i_height as u32, 109 | }; 110 | 111 | gbr_with_alpha_to_rgba( 112 | &planar_image_with_alpha, 113 | &mut target_rgba, 114 | i_width as u32 * 4, 115 | YuvRange::Limited, 116 | ) 117 | .unwrap(); 118 | } 119 | 120 | fn fuzz_yuv_444_p16(i_width: u8, i_height: u8, y_value: u8, u_value: u8, v_value: u8) { 121 | if i_height == 0 || i_width == 0 { 122 | return; 123 | } 124 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 125 | let a_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 126 | let u_plane = vec![u_value as u16; i_width as usize * i_height as usize]; 127 | let v_plane = vec![v_value as u16; i_width as usize * i_height as usize]; 128 | 129 | let planar_image = YuvPlanarImage { 130 | y_plane: &y_plane, 131 | y_stride: i_width as u32, 132 | u_plane: &u_plane, 133 | u_stride: i_width as u32, 134 | v_plane: &v_plane, 135 | v_stride: i_width as u32, 136 | width: i_width as u32, 137 | height: i_height as u32, 138 | }; 139 | 140 | let mut target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 141 | 142 | gb10_to_rgb10( 143 | &planar_image, 144 | &mut target_rgb, 145 | i_width as u32 * 3, 146 | YuvRange::Limited, 147 | ) 148 | .unwrap(); 149 | 150 | gb10_to_rgb10( 151 | &planar_image, 152 | &mut target_rgb, 153 | i_width as u32 * 3, 154 | YuvRange::Full, 155 | ) 156 | .unwrap(); 157 | 158 | let mut target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 159 | 160 | gb10_to_rgba10( 161 | &planar_image, 162 | &mut target_rgba, 163 | i_width as u32 * 4, 164 | YuvRange::Limited, 165 | ) 166 | .unwrap(); 167 | 168 | gb10_to_rgba10( 169 | &planar_image, 170 | &mut target_rgba, 171 | i_width as u32 * 4, 172 | YuvRange::Full, 173 | ) 174 | .unwrap(); 175 | 176 | let planar_image_with_alpha = YuvPlanarImageWithAlpha { 177 | y_plane: &y_plane, 178 | y_stride: i_width as u32, 179 | u_plane: &u_plane, 180 | u_stride: i_width as u32, 181 | v_plane: &v_plane, 182 | v_stride: i_width as u32, 183 | a_plane: &a_plane, 184 | a_stride: i_width as u32, 185 | width: i_width as u32, 186 | height: i_height as u32, 187 | }; 188 | 189 | gb10_alpha_to_rgba10( 190 | &planar_image_with_alpha, 191 | &mut target_rgba, 192 | i_width as u32 * 4, 193 | YuvRange::Limited, 194 | ) 195 | .unwrap(); 196 | } 197 | -------------------------------------------------------------------------------- /fuzz/rdp/rdp.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | use arbitrary::{Arbitrary, Unstructured}; 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | rdp_abgr_to_yuv444, rdp_argb_to_yuv444, rdp_bgr_to_yuv444, rdp_bgra_to_yuv444, 35 | rdp_rgb_to_yuv444, rdp_rgba_to_yuv444, rdp_yuv444_to_abgr, rdp_yuv444_to_argb, 36 | rdp_yuv444_to_bgra, rdp_yuv444_to_rgb, rdp_yuv444_to_rgba, BufferStoreMut, YuvPlanarImageMut, 37 | }; 38 | 39 | fuzz_target!(|data: (WidthStrides, u8)| { 40 | fuzz_yuv_444(data.0, data.1); 41 | }); 42 | 43 | fn fuzz_yuv_444(i_width: WidthStrides, i_height: u8) { 44 | let [i_stride, y_stride, u_stride, v_stride] = i_width.1; 45 | if i_height == 0 || i_width.0 == 0 { 46 | return; 47 | } 48 | let y_plane = vec![0i16; y_stride as usize * (i_height - 1) as usize + i_width.0 as usize]; 49 | let u_plane = vec![0i16; u_stride as usize * (i_height - 1) as usize + i_width.0 as usize]; 50 | let v_plane = vec![0i16; v_stride as usize * (i_height - 1) as usize + i_width.0 as usize]; 51 | 52 | let mut planar_image = YuvPlanarImageMut { 53 | y_plane: BufferStoreMut::Owned(y_plane), 54 | y_stride, 55 | u_plane: BufferStoreMut::Owned(u_plane), 56 | u_stride, 57 | v_plane: BufferStoreMut::Owned(v_plane), 58 | v_stride, 59 | width: i_width.0 as u32, 60 | height: i_height as u32, 61 | }; 62 | 63 | let src_rgb = vec![0u8; (i_stride as usize * (i_height - 1) as usize + i_width.0 as usize) * 3]; 64 | 65 | rdp_rgb_to_yuv444(&mut planar_image, &src_rgb, i_stride * 3).unwrap(); 66 | rdp_bgr_to_yuv444(&mut planar_image, &src_rgb, i_stride * 3).unwrap(); 67 | 68 | let src_rgba = 69 | vec![0u8; (i_stride as usize * (i_height - 1) as usize + i_width.0 as usize) * 4]; 70 | 71 | rdp_rgba_to_yuv444(&mut planar_image, &src_rgba, i_stride * 4).unwrap(); 72 | rdp_bgra_to_yuv444(&mut planar_image, &src_rgba, i_stride * 4).unwrap(); 73 | rdp_abgr_to_yuv444(&mut planar_image, &src_rgba, i_stride * 4).unwrap(); 74 | rdp_argb_to_yuv444(&mut planar_image, &src_rgba, i_stride * 4).unwrap(); 75 | 76 | let fixed_planar = planar_image.to_fixed(); 77 | 78 | let mut target_rgba = 79 | vec![0u8; (i_stride as usize * (i_height - 1) as usize + i_width.0 as usize) * 4]; 80 | 81 | rdp_yuv444_to_rgba(&fixed_planar, &mut target_rgba, i_stride * 4).unwrap(); 82 | rdp_yuv444_to_abgr(&fixed_planar, &mut target_rgba, i_stride * 4).unwrap(); 83 | rdp_yuv444_to_argb(&fixed_planar, &mut target_rgba, i_stride * 4).unwrap(); 84 | rdp_yuv444_to_bgra(&fixed_planar, &mut target_rgba, i_stride * 4).unwrap(); 85 | 86 | let mut target_rgb = 87 | vec![0u8; (i_stride as usize * (i_height - 1) as usize + i_width.0 as usize) * 3]; 88 | 89 | rdp_yuv444_to_rgb(&fixed_planar, &mut target_rgb, i_stride * 3).unwrap(); 90 | } 91 | 92 | #[derive(Debug, Clone, Copy)] 93 | struct WidthStrides(u8, [u32; 4]); 94 | 95 | impl<'a> Arbitrary<'a> for WidthStrides { 96 | fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result { 97 | let width = u8::arbitrary(u)?; 98 | let max_stride = u8::MAX - width; 99 | let strides: Vec = (0..4) 100 | .map(|_| (width + u.int_in_range(0..=max_stride).unwrap()) as u32) 101 | .collect(); 102 | 103 | Ok(WidthStrides(width, strides.try_into().unwrap())) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /fuzz/rgb16_to_nv16/rgb16_to_nv16.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | rgb10_to_p010, rgb10_to_p210, rgb10_to_p410, rgba10_to_p010, rgba10_to_p210, rgba10_to_p410, 35 | BufferStoreMut, YuvBiPlanarImageMut, YuvRange, YuvStandardMatrix, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8)| { 39 | fuzz_yuv_420(data.0, data.1, data.2, data.3); 40 | fuzz_yuv_422(data.0, data.1, data.2, data.3); 41 | fuzz_yuv_444(data.0, data.1, data.2, data.3); 42 | }); 43 | 44 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u8, u_value: u8) { 45 | if i_height == 0 || i_width == 0 { 46 | return; 47 | } 48 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 49 | let uv_plane = 50 | vec![u_value as u16; (i_width as usize).div_ceil(2) * (i_height as usize).div_ceil(2) * 2]; 51 | 52 | let mut bi_planar_image = YuvBiPlanarImageMut { 53 | y_plane: BufferStoreMut::Owned(y_plane), 54 | y_stride: i_width as u32, 55 | uv_plane: BufferStoreMut::Owned(uv_plane), 56 | uv_stride: (i_width as u32).div_ceil(2) * 2, 57 | width: i_width as u32, 58 | height: i_height as u32, 59 | }; 60 | 61 | let target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 62 | 63 | rgb10_to_p010( 64 | &mut bi_planar_image, 65 | &target_rgb, 66 | i_width as u32 * 3, 67 | YuvRange::Limited, 68 | YuvStandardMatrix::Bt601, 69 | ) 70 | .unwrap(); 71 | 72 | let target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 73 | 74 | rgba10_to_p010( 75 | &mut bi_planar_image, 76 | &target_rgba, 77 | i_width as u32 * 4, 78 | YuvRange::Limited, 79 | YuvStandardMatrix::Bt601, 80 | ) 81 | .unwrap(); 82 | } 83 | 84 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u8, u_value: u8) { 85 | if i_height == 0 || i_width == 0 { 86 | return; 87 | } 88 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 89 | let uv_plane = vec![u_value as u16; (i_width as usize).div_ceil(2) * i_height as usize * 2]; 90 | 91 | let mut planar_image = YuvBiPlanarImageMut { 92 | y_plane: BufferStoreMut::Owned(y_plane), 93 | y_stride: i_width as u32, 94 | uv_plane: BufferStoreMut::Owned(uv_plane), 95 | uv_stride: (i_width as u32).div_ceil(2) * 2, 96 | width: i_width as u32, 97 | height: i_height as u32, 98 | }; 99 | 100 | let target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 101 | 102 | rgb10_to_p210( 103 | &mut planar_image, 104 | &target_rgb, 105 | i_width as u32 * 3, 106 | YuvRange::Limited, 107 | YuvStandardMatrix::Bt601, 108 | ) 109 | .unwrap(); 110 | 111 | let target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 112 | 113 | rgba10_to_p210( 114 | &mut planar_image, 115 | &target_rgba, 116 | i_width as u32 * 4, 117 | YuvRange::Limited, 118 | YuvStandardMatrix::Bt601, 119 | ) 120 | .unwrap(); 121 | } 122 | 123 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, u_value: u8) { 124 | if i_height == 0 || i_width == 0 { 125 | return; 126 | } 127 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 128 | let uv_plane = vec![u_value as u16; i_width as usize * i_height as usize * 2]; 129 | 130 | let mut planar_image = YuvBiPlanarImageMut { 131 | y_plane: BufferStoreMut::Owned(y_plane), 132 | y_stride: i_width as u32, 133 | uv_plane: BufferStoreMut::Owned(uv_plane), 134 | uv_stride: i_width as u32 * 2, 135 | width: i_width as u32, 136 | height: i_height as u32, 137 | }; 138 | 139 | let target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 140 | 141 | rgb10_to_p410( 142 | &mut planar_image, 143 | &target_rgb, 144 | i_width as u32 * 3, 145 | YuvRange::Limited, 146 | YuvStandardMatrix::Bt601, 147 | ) 148 | .unwrap(); 149 | 150 | let target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 151 | 152 | rgba10_to_p410( 153 | &mut planar_image, 154 | &target_rgba, 155 | i_width as u32 * 4, 156 | YuvRange::Limited, 157 | YuvStandardMatrix::Bt601, 158 | ) 159 | .unwrap(); 160 | } 161 | -------------------------------------------------------------------------------- /fuzz/rgb_to_f16/rgb_to_f16.rs: -------------------------------------------------------------------------------- 1 | #![feature(f16)] 2 | /* 3 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without modification, 6 | * are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 11 | * 2. Redistributions in binary form must reproduce the above copyright notice, 12 | * this list of conditions and the following disclaimer in the documentation 13 | * and/or other materials provided with the distribution. 14 | * 15 | * 3. Neither the name of the copyright holder nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | #![no_main] 31 | use core::f16; 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | convert_plane16_to_f16, convert_plane_f16_to_planar, convert_plane_to_f16, convert_rgb_to_f16, 35 | convert_rgba_to_f16, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8)| { 39 | fuzz_f16_converter(data.0, data.1, data.2); 40 | }); 41 | 42 | fn fuzz_f16_converter(i_width: u8, i_height: u8, y_value: u8) { 43 | if i_height == 0 || i_width == 0 { 44 | return; 45 | } 46 | let src_plane = vec![y_value; i_height as usize * i_width as usize]; 47 | let mut dst_plane = vec![0.; i_width as usize * i_height as usize]; 48 | convert_plane_to_f16( 49 | &src_plane, 50 | i_width as usize, 51 | &mut dst_plane, 52 | i_width as usize, 53 | i_width as usize, 54 | i_height as usize, 55 | ) 56 | .unwrap(); 57 | 58 | let src_plane1 = vec![y_value; i_height as usize * i_width as usize * 3]; 59 | let mut dst_plane1 = vec![0.; i_width as usize * i_height as usize * 3]; 60 | convert_rgb_to_f16( 61 | &src_plane1, 62 | i_width as usize * 3, 63 | &mut dst_plane1, 64 | i_width as usize * 3, 65 | i_width as usize, 66 | i_height as usize, 67 | ) 68 | .unwrap(); 69 | 70 | let src_plane2 = vec![y_value; i_height as usize * i_width as usize * 4]; 71 | let mut dst_plane2 = vec![0.; i_width as usize * i_height as usize * 4]; 72 | convert_rgba_to_f16( 73 | &src_plane2, 74 | i_width as usize * 4, 75 | &mut dst_plane2, 76 | i_width as usize * 4, 77 | i_width as usize, 78 | i_height as usize, 79 | ) 80 | .unwrap(); 81 | 82 | let src_plane3 = vec![y_value as u16; i_height as usize * i_width as usize]; 83 | let mut dst_plane3 = vec![0.; i_width as usize * i_height as usize]; 84 | convert_plane16_to_f16( 85 | &src_plane3, 86 | i_width as usize, 87 | &mut dst_plane3, 88 | i_width as usize, 89 | 10, 90 | i_width as usize, 91 | i_height as usize, 92 | ) 93 | .unwrap(); 94 | 95 | let src_plane4 = vec![y_value as f16; i_height as usize * i_width as usize]; 96 | let mut dst_plane4 = vec![0u8; i_width as usize * i_height as usize]; 97 | convert_plane_f16_to_planar( 98 | &src_plane4, 99 | i_width as usize, 100 | &mut dst_plane4, 101 | i_width as usize, 102 | i_width as usize, 103 | i_height as usize, 104 | ) 105 | .unwrap(); 106 | } 107 | -------------------------------------------------------------------------------- /fuzz/rgb_to_nv/rgb_to_nv.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | rgb_to_yuv_nv12, rgb_to_yuv_nv16, rgb_to_yuv_nv24, rgba_to_yuv_nv12, rgba_to_yuv_nv16, 35 | rgba_to_yuv_nv24, BufferStoreMut, YuvBiPlanarImageMut, YuvConversionMode, YuvRange, 36 | YuvStandardMatrix, 37 | }; 38 | 39 | fuzz_target!(|data: (u8, u8, u8, u8, u8, u8)| { 40 | let fast_mode = match data.5 % 3 { 41 | 0 => YuvConversionMode::Fast, 42 | 1 => YuvConversionMode::Balanced, 43 | _ => YuvConversionMode::Professional, 44 | }; 45 | fuzz_yuv_420(data.0, data.1, data.2, data.3, fast_mode); 46 | fuzz_yuv_422(data.0, data.1, data.2, data.3, fast_mode); 47 | fuzz_yuv_444(data.0, data.1, data.2, data.3, fast_mode); 48 | }); 49 | 50 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u8, u_value: u8, mode: YuvConversionMode) { 51 | if i_height == 0 || i_width == 0 { 52 | return; 53 | } 54 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 55 | let uv_plane = 56 | vec![u_value; (i_width as usize).div_ceil(2) * (i_height as usize).div_ceil(2) * 2]; 57 | 58 | let mut bi_planar_image = YuvBiPlanarImageMut { 59 | y_plane: BufferStoreMut::Owned(y_plane), 60 | y_stride: i_width as u32, 61 | uv_plane: BufferStoreMut::Owned(uv_plane), 62 | uv_stride: (i_width as u32).div_ceil(2) * 2, 63 | width: i_width as u32, 64 | height: i_height as u32, 65 | }; 66 | 67 | let target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 68 | 69 | rgb_to_yuv_nv12( 70 | &mut bi_planar_image, 71 | &target_rgb, 72 | i_width as u32 * 3, 73 | YuvRange::Limited, 74 | YuvStandardMatrix::Bt601, 75 | mode, 76 | ) 77 | .unwrap(); 78 | 79 | let target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 80 | 81 | rgba_to_yuv_nv12( 82 | &mut bi_planar_image, 83 | &target_rgba, 84 | i_width as u32 * 4, 85 | YuvRange::Limited, 86 | YuvStandardMatrix::Bt601, 87 | mode, 88 | ) 89 | .unwrap(); 90 | } 91 | 92 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u8, u_value: u8, mode: YuvConversionMode) { 93 | if i_height == 0 || i_width == 0 { 94 | return; 95 | } 96 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 97 | let uv_plane = vec![u_value; (i_width as usize).div_ceil(2) * i_height as usize * 2]; 98 | 99 | let mut planar_image = YuvBiPlanarImageMut { 100 | y_plane: BufferStoreMut::Owned(y_plane), 101 | y_stride: i_width as u32, 102 | uv_plane: BufferStoreMut::Owned(uv_plane), 103 | uv_stride: (i_width as u32).div_ceil(2) * 2, 104 | width: i_width as u32, 105 | height: i_height as u32, 106 | }; 107 | 108 | let target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 109 | 110 | rgb_to_yuv_nv16( 111 | &mut planar_image, 112 | &target_rgb, 113 | i_width as u32 * 3, 114 | YuvRange::Limited, 115 | YuvStandardMatrix::Bt601, 116 | mode, 117 | ) 118 | .unwrap(); 119 | 120 | let target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 121 | 122 | rgba_to_yuv_nv16( 123 | &mut planar_image, 124 | &target_rgba, 125 | i_width as u32 * 4, 126 | YuvRange::Limited, 127 | YuvStandardMatrix::Bt601, 128 | mode, 129 | ) 130 | .unwrap(); 131 | } 132 | 133 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, u_value: u8, mode: YuvConversionMode) { 134 | if i_height == 0 || i_width == 0 { 135 | return; 136 | } 137 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 138 | let uv_plane = vec![u_value; i_width as usize * i_height as usize * 2]; 139 | 140 | let mut planar_image = YuvBiPlanarImageMut { 141 | y_plane: BufferStoreMut::Owned(y_plane), 142 | y_stride: i_width as u32, 143 | uv_plane: BufferStoreMut::Owned(uv_plane), 144 | uv_stride: i_width as u32 * 2, 145 | width: i_width as u32, 146 | height: i_height as u32, 147 | }; 148 | 149 | let target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 150 | 151 | rgb_to_yuv_nv24( 152 | &mut planar_image, 153 | &target_rgb, 154 | i_width as u32 * 3, 155 | YuvRange::Limited, 156 | YuvStandardMatrix::Bt601, 157 | mode, 158 | ) 159 | .unwrap(); 160 | 161 | let target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 162 | 163 | rgba_to_yuv_nv24( 164 | &mut planar_image, 165 | &target_rgba, 166 | i_width as u32 * 4, 167 | YuvRange::Limited, 168 | YuvStandardMatrix::Bt601, 169 | mode, 170 | ) 171 | .unwrap(); 172 | } 173 | -------------------------------------------------------------------------------- /fuzz/rgb_to_y/rgb_to_y.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | rgb_to_yuv400, rgba_to_yuv400, BufferStoreMut, YuvGrayImageMut, YuvRange, YuvStandardMatrix, 35 | }; 36 | 37 | fuzz_target!(|data: (u8, u8, u8)| { 38 | fuzz_yuv_400(data.0, data.1, data.2); 39 | }); 40 | 41 | fn fuzz_yuv_400(i_width: u8, i_height: u8, y_value: u8) { 42 | if i_height == 0 || i_width == 0 { 43 | return; 44 | } 45 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 46 | 47 | let mut planar_image = YuvGrayImageMut { 48 | y_plane: BufferStoreMut::Owned(y_plane), 49 | y_stride: i_width as u32, 50 | width: i_width as u32, 51 | height: i_height as u32, 52 | }; 53 | 54 | let target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 55 | 56 | rgb_to_yuv400( 57 | &mut planar_image, 58 | &target_rgb, 59 | i_width as u32 * 3, 60 | YuvRange::Limited, 61 | YuvStandardMatrix::Bt601, 62 | ) 63 | .unwrap(); 64 | 65 | let target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 66 | 67 | rgba_to_yuv400( 68 | &mut planar_image, 69 | &target_rgba, 70 | i_width as u32 * 4, 71 | YuvRange::Limited, 72 | YuvStandardMatrix::Bt601, 73 | ) 74 | .unwrap(); 75 | } 76 | -------------------------------------------------------------------------------- /fuzz/shuffle/shuffle.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{bgr_to_rgb, rgba_to_bgr, rgba_to_bgra}; 34 | 35 | fuzz_target!(|data: (u8, u8, bool, bool)| { 36 | fuzz_shuffler(data.0, data.1, data.2, data.3); 37 | }); 38 | 39 | fn fuzz_shuffler(i_width: u8, i_height: u8, src_rgba: bool, dst_rgba: bool) { 40 | if i_height == 0 || i_width == 0 { 41 | return; 42 | } 43 | let src_chans = if src_rgba { 4 } else { 3 }; 44 | let dst_chans = if dst_rgba { 4 } else { 3 }; 45 | let src_data = vec![126u8; src_chans * i_width as usize * i_height as usize]; 46 | let mut dst_data = vec![50u8; dst_chans * i_width as usize * i_height as usize]; 47 | 48 | let shuffler = if src_rgba && dst_rgba { 49 | rgba_to_bgra 50 | } else if src_rgba { 51 | rgba_to_bgr 52 | } else { 53 | bgr_to_rgb 54 | }; 55 | shuffler( 56 | &src_data, 57 | src_chans as u32 * i_width as u32, 58 | &mut dst_data, 59 | dst_chans as u32 * i_width as u32, 60 | i_width as u32, 61 | i_height as u32, 62 | ) 63 | .unwrap(); 64 | } 65 | -------------------------------------------------------------------------------- /fuzz/y16_to_rgb16/y16_to_rgb16.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | use libfuzzer_sys::fuzz_target; 32 | use yuv::{y010_to_rgb10, y010_to_rgba10, YuvGrayImage, YuvRange, YuvStandardMatrix}; 33 | 34 | fuzz_target!(|data: (u8, u8, u8)| { 35 | fuzz_yuv(data.0, data.1, data.2); 36 | }); 37 | 38 | fn fuzz_yuv(i_width: u8, i_height: u8, y_value: u8) { 39 | if i_height == 0 || i_width == 0 { 40 | return; 41 | } 42 | 43 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 44 | 45 | let planar_image = YuvGrayImage { 46 | y_plane: &y_plane, 47 | y_stride: i_width as u32, 48 | width: i_width as u32, 49 | height: i_height as u32, 50 | }; 51 | 52 | let mut target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 53 | 54 | y010_to_rgb10( 55 | &planar_image, 56 | &mut target_rgb, 57 | i_width as u32 * 3, 58 | YuvRange::Limited, 59 | YuvStandardMatrix::Bt601, 60 | ) 61 | .unwrap(); 62 | 63 | let mut target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 64 | 65 | y010_to_rgba10( 66 | &planar_image, 67 | &mut target_rgba, 68 | i_width as u32 * 4, 69 | YuvRange::Limited, 70 | YuvStandardMatrix::Bt601, 71 | ) 72 | .unwrap(); 73 | } 74 | -------------------------------------------------------------------------------- /fuzz/y_to_rgb/y_to_rgb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | use libfuzzer_sys::fuzz_target; 32 | use yuv::{ 33 | yuv400_alpha_to_rgba, yuv400_to_rgb, yuv400_to_rgba, YuvGrayAlphaImage, YuvGrayImage, YuvRange, 34 | YuvStandardMatrix, 35 | }; 36 | 37 | fuzz_target!(|data: (u8, u8, u8)| { 38 | fuzz_yuv(data.0, data.1, data.2); 39 | }); 40 | 41 | fn fuzz_yuv(i_width: u8, i_height: u8, y_value: u8) { 42 | if i_height == 0 || i_width == 0 { 43 | return; 44 | } 45 | 46 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 47 | 48 | let planar_image = YuvGrayImage { 49 | y_plane: &y_plane, 50 | y_stride: i_width as u32, 51 | width: i_width as u32, 52 | height: i_height as u32, 53 | }; 54 | 55 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 56 | 57 | yuv400_to_rgb( 58 | &planar_image, 59 | &mut target_rgb, 60 | i_width as u32 * 3, 61 | YuvRange::Limited, 62 | YuvStandardMatrix::Bt601, 63 | ) 64 | .unwrap(); 65 | 66 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 67 | 68 | yuv400_to_rgba( 69 | &planar_image, 70 | &mut target_rgba, 71 | i_width as u32 * 4, 72 | YuvRange::Limited, 73 | YuvStandardMatrix::Bt601, 74 | ) 75 | .unwrap(); 76 | 77 | let a_plane = vec![y_value; i_height as usize * i_width as usize]; 78 | 79 | let planar_image_with_alpha = YuvGrayAlphaImage { 80 | y_plane: &y_plane, 81 | y_stride: i_width as u32, 82 | a_plane: &a_plane, 83 | a_stride: i_width as u32, 84 | width: i_width as u32, 85 | height: i_height as u32, 86 | }; 87 | 88 | yuv400_alpha_to_rgba( 89 | &planar_image_with_alpha, 90 | &mut target_rgba, 91 | i_width as u32 * 4, 92 | YuvRange::Limited, 93 | YuvStandardMatrix::Bt601, 94 | ) 95 | .unwrap(); 96 | } 97 | -------------------------------------------------------------------------------- /fuzz/yuv16_to_ar30/yuv16_to_ar30.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | i010_to_ar30, i210_to_ar30, i410_to_ar30, Rgb30ByteOrder, YuvPlanarImage, YuvRange, 35 | YuvStandardMatrix, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8, u8)| { 39 | fuzz_yuv_420(data.0, data.1, data.2 as u16, data.3 as u16, data.4 as u16); 40 | fuzz_yuv_422(data.0, data.1, data.2 as u16, data.3 as u16, data.4 as u16); 41 | fuzz_yuv_444(data.0, data.1, data.2 as u16, data.3 as u16, data.4 as u16); 42 | }); 43 | 44 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u16, u_value: u16, v_value: u16) { 45 | if i_height == 0 || i_width == 0 { 46 | return; 47 | } 48 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 49 | let u_plane = vec![u_value; (i_width as usize).div_ceil(2) * (i_height as usize).div_ceil(2)]; 50 | let v_plane = vec![v_value; (i_width as usize).div_ceil(2) * (i_height as usize).div_ceil(2)]; 51 | 52 | let planar_image = YuvPlanarImage { 53 | y_plane: &y_plane, 54 | y_stride: i_width as u32, 55 | u_plane: &u_plane, 56 | u_stride: (i_width as u32).div_ceil(2), 57 | v_plane: &v_plane, 58 | v_stride: (i_width as u32).div_ceil(2), 59 | width: i_width as u32, 60 | height: i_height as u32, 61 | }; 62 | 63 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 64 | 65 | i010_to_ar30( 66 | &planar_image, 67 | &mut target_rgba, 68 | i_width as u32 * 4, 69 | Rgb30ByteOrder::Host, 70 | YuvRange::Limited, 71 | YuvStandardMatrix::Bt601, 72 | ) 73 | .unwrap(); 74 | } 75 | 76 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u16, u_value: u16, v_value: u16) { 77 | if i_height == 0 || i_width == 0 { 78 | return; 79 | } 80 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 81 | let u_plane = vec![u_value; (i_width as usize).div_ceil(2) * i_height as usize]; 82 | let v_plane = vec![v_value; (i_width as usize).div_ceil(2) * i_height as usize]; 83 | 84 | let planar_image = YuvPlanarImage { 85 | y_plane: &y_plane, 86 | y_stride: i_width as u32, 87 | u_plane: &u_plane, 88 | u_stride: (i_width as u32).div_ceil(2), 89 | v_plane: &v_plane, 90 | v_stride: (i_width as u32).div_ceil(2), 91 | width: i_width as u32, 92 | height: i_height as u32, 93 | }; 94 | 95 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 96 | 97 | i210_to_ar30( 98 | &planar_image, 99 | &mut target_rgba, 100 | i_width as u32 * 4, 101 | Rgb30ByteOrder::Host, 102 | YuvRange::Limited, 103 | YuvStandardMatrix::Bt601, 104 | ) 105 | .unwrap(); 106 | } 107 | 108 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u16, u_value: u16, v_value: u16) { 109 | if i_height == 0 || i_width == 0 { 110 | return; 111 | } 112 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 113 | let u_plane = vec![u_value; i_width as usize * i_height as usize]; 114 | let v_plane = vec![v_value; i_width as usize * i_height as usize]; 115 | 116 | let planar_image = YuvPlanarImage { 117 | y_plane: &y_plane, 118 | y_stride: i_width as u32, 119 | u_plane: &u_plane, 120 | u_stride: i_width as u32, 121 | v_plane: &v_plane, 122 | v_stride: i_width as u32, 123 | width: i_width as u32, 124 | height: i_height as u32, 125 | }; 126 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 127 | 128 | i410_to_ar30( 129 | &planar_image, 130 | &mut target_rgba, 131 | i_width as u32 * 4, 132 | Rgb30ByteOrder::Network, 133 | YuvRange::Limited, 134 | YuvStandardMatrix::Bt601, 135 | ) 136 | .unwrap(); 137 | } 138 | -------------------------------------------------------------------------------- /fuzz/yuv_nv10_to_rgb/yuv_nv10_to_rgb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | p010_to_ar30, p010_to_rgb, p210_to_ar30, p210_to_rgb, p210_to_rgba, p410_to_rgb, p410_to_rgba, 35 | Rgb30ByteOrder, YuvBiPlanarImage, YuvConversionMode, YuvRange, YuvStandardMatrix, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8, u8)| { 39 | let mode = match data.5 % 3 { 40 | 0 => YuvConversionMode::Fast, 41 | 1 => YuvConversionMode::Balanced, 42 | _ => YuvConversionMode::Professional, 43 | }; 44 | fuzz_yuv_420(data.0, data.1, data.2, data.3, mode); 45 | fuzz_yuv_422(data.0, data.1, data.2, data.3, mode); 46 | fuzz_yuv_444(data.0, data.1, data.2, data.3, mode); 47 | }); 48 | 49 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u8, uv_value: u8, mode: YuvConversionMode) { 50 | if i_height == 0 || i_width == 0 { 51 | return; 52 | } 53 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 54 | let uv_plane = 55 | vec![uv_value as u16; (i_width as usize).div_ceil(2) * 2 * (i_height as usize).div_ceil(2)]; 56 | 57 | let planar_image = YuvBiPlanarImage { 58 | y_plane: &y_plane, 59 | y_stride: i_width as u32, 60 | uv_plane: &uv_plane, 61 | uv_stride: (i_width as u32).div_ceil(2) * 2, 62 | width: i_width as u32, 63 | height: i_height as u32, 64 | }; 65 | 66 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 67 | 68 | p010_to_rgb( 69 | &planar_image, 70 | &mut target_rgb, 71 | i_width as u32 * 3, 72 | YuvRange::Limited, 73 | YuvStandardMatrix::Bt601, 74 | mode, 75 | ) 76 | .unwrap(); 77 | 78 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 79 | 80 | p010_to_rgb( 81 | &planar_image, 82 | &mut target_rgba, 83 | i_width as u32 * 4, 84 | YuvRange::Limited, 85 | YuvStandardMatrix::Bt601, 86 | mode, 87 | ) 88 | .unwrap(); 89 | 90 | p010_to_ar30( 91 | &planar_image, 92 | &mut target_rgba, 93 | i_width as u32 * 4, 94 | Rgb30ByteOrder::Host, 95 | YuvRange::Limited, 96 | YuvStandardMatrix::Bt601, 97 | ) 98 | .unwrap(); 99 | } 100 | 101 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u8, uv_value: u8, mode: YuvConversionMode) { 102 | if i_height == 0 || i_width == 0 { 103 | return; 104 | } 105 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 106 | let uv_plane = vec![uv_value as u16; (i_width as usize).div_ceil(2) * 2 * i_height as usize]; 107 | 108 | let planar_image = YuvBiPlanarImage { 109 | y_plane: &y_plane, 110 | y_stride: i_width as u32, 111 | uv_plane: &uv_plane, 112 | uv_stride: (i_width as u32).div_ceil(2) * 2, 113 | width: i_width as u32, 114 | height: i_height as u32, 115 | }; 116 | 117 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 118 | 119 | p210_to_rgb( 120 | &planar_image, 121 | &mut target_rgb, 122 | i_width as u32 * 3, 123 | YuvRange::Limited, 124 | YuvStandardMatrix::Bt601, 125 | mode, 126 | ) 127 | .unwrap(); 128 | 129 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 130 | 131 | p210_to_rgba( 132 | &planar_image, 133 | &mut target_rgba, 134 | i_width as u32 * 4, 135 | YuvRange::Limited, 136 | YuvStandardMatrix::Bt601, 137 | mode, 138 | ) 139 | .unwrap(); 140 | 141 | p210_to_ar30( 142 | &planar_image, 143 | &mut target_rgba, 144 | i_width as u32 * 4, 145 | Rgb30ByteOrder::Host, 146 | YuvRange::Limited, 147 | YuvStandardMatrix::Bt601, 148 | ) 149 | .unwrap(); 150 | } 151 | 152 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, uv_value: u8, mode: YuvConversionMode) { 153 | if i_height == 0 || i_width == 0 { 154 | return; 155 | } 156 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 157 | let uv_plane = vec![uv_value as u16; i_width as usize * 2 * i_height as usize]; 158 | 159 | let planar_image = YuvBiPlanarImage { 160 | y_plane: &y_plane, 161 | y_stride: i_width as u32, 162 | uv_plane: &uv_plane, 163 | uv_stride: i_width as u32 * 2, 164 | width: i_width as u32, 165 | height: i_height as u32, 166 | }; 167 | 168 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 169 | 170 | p410_to_rgb( 171 | &planar_image, 172 | &mut target_rgb, 173 | i_width as u32 * 3, 174 | YuvRange::Limited, 175 | YuvStandardMatrix::Bt601, 176 | mode, 177 | ) 178 | .unwrap(); 179 | 180 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 181 | 182 | p410_to_rgba( 183 | &planar_image, 184 | &mut target_rgba, 185 | i_width as u32 * 4, 186 | YuvRange::Limited, 187 | YuvStandardMatrix::Bt601, 188 | mode, 189 | ) 190 | .unwrap(); 191 | } 192 | -------------------------------------------------------------------------------- /fuzz/yuv_nv16_to_rgb16/yuv_nv16_to_rgb16.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | p010_to_rgb10, p010_to_rgba10, p210_to_rgb10, p210_to_rgba10, p410_to_rgb10, p410_to_rgba10, 35 | YuvBiPlanarImage, YuvRange, YuvStandardMatrix, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8)| { 39 | fuzz_yuv_420(data.0, data.1, data.2, data.3); 40 | fuzz_yuv_422(data.0, data.1, data.2, data.3); 41 | fuzz_yuv_444(data.0, data.1, data.2, data.3); 42 | }); 43 | 44 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u8, uv_value: u8) { 45 | if i_height == 0 || i_width == 0 { 46 | return; 47 | } 48 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 49 | let uv_plane = 50 | vec![uv_value as u16; (i_width as usize).div_ceil(2) * 2 * (i_height as usize).div_ceil(2)]; 51 | 52 | let planar_image = YuvBiPlanarImage { 53 | y_plane: &y_plane, 54 | y_stride: i_width as u32, 55 | uv_plane: &uv_plane, 56 | uv_stride: (i_width as u32).div_ceil(2) * 2, 57 | width: i_width as u32, 58 | height: i_height as u32, 59 | }; 60 | 61 | let mut target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 62 | 63 | p010_to_rgb10( 64 | &planar_image, 65 | &mut target_rgb, 66 | i_width as u32 * 3, 67 | YuvRange::Limited, 68 | YuvStandardMatrix::Bt601, 69 | ) 70 | .unwrap(); 71 | 72 | let mut target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 73 | 74 | p010_to_rgba10( 75 | &planar_image, 76 | &mut target_rgba, 77 | i_width as u32 * 4, 78 | YuvRange::Limited, 79 | YuvStandardMatrix::Bt601, 80 | ) 81 | .unwrap(); 82 | } 83 | 84 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u8, uv_value: u8) { 85 | if i_height == 0 || i_width == 0 { 86 | return; 87 | } 88 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 89 | let uv_plane = vec![uv_value as u16; (i_width as usize).div_ceil(2) * 2 * i_height as usize]; 90 | 91 | let planar_image = YuvBiPlanarImage { 92 | y_plane: &y_plane, 93 | y_stride: i_width as u32, 94 | uv_plane: &uv_plane, 95 | uv_stride: (i_width as u32).div_ceil(2) * 2, 96 | width: i_width as u32, 97 | height: i_height as u32, 98 | }; 99 | 100 | let mut target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 101 | 102 | p210_to_rgb10( 103 | &planar_image, 104 | &mut target_rgb, 105 | i_width as u32 * 3, 106 | YuvRange::Limited, 107 | YuvStandardMatrix::Bt601, 108 | ) 109 | .unwrap(); 110 | 111 | let mut target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 112 | 113 | p210_to_rgba10( 114 | &planar_image, 115 | &mut target_rgba, 116 | i_width as u32 * 4, 117 | YuvRange::Limited, 118 | YuvStandardMatrix::Bt601, 119 | ) 120 | .unwrap(); 121 | } 122 | 123 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, uv_value: u8) { 124 | if i_height == 0 || i_width == 0 { 125 | return; 126 | } 127 | let y_plane = vec![y_value as u16; i_height as usize * i_width as usize]; 128 | let uv_plane = vec![uv_value as u16; i_width as usize * 2 * i_height as usize]; 129 | 130 | let planar_image = YuvBiPlanarImage { 131 | y_plane: &y_plane, 132 | y_stride: i_width as u32, 133 | uv_plane: &uv_plane, 134 | uv_stride: i_width as u32 * 2, 135 | width: i_width as u32, 136 | height: i_height as u32, 137 | }; 138 | 139 | let mut target_rgb = vec![0u16; i_width as usize * i_height as usize * 3]; 140 | 141 | p410_to_rgb10( 142 | &planar_image, 143 | &mut target_rgb, 144 | i_width as u32 * 3, 145 | YuvRange::Limited, 146 | YuvStandardMatrix::Bt601, 147 | ) 148 | .unwrap(); 149 | 150 | let mut target_rgba = vec![0u16; i_width as usize * i_height as usize * 4]; 151 | 152 | p410_to_rgba10( 153 | &planar_image, 154 | &mut target_rgba, 155 | i_width as u32 * 4, 156 | YuvRange::Limited, 157 | YuvStandardMatrix::Bt601, 158 | ) 159 | .unwrap(); 160 | } 161 | -------------------------------------------------------------------------------- /fuzz/yuv_nv_to_rgb/yuv_nv_to_rgb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | yuv_nv16_to_rgb, yuv_nv16_to_rgba, yuv_nv21_to_rgb, yuv_nv21_to_rgba, yuv_nv24_to_rgb, 35 | yuv_nv24_to_rgba, YuvBiPlanarImage, YuvConversionMode, YuvRange, YuvStandardMatrix, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8, bool)| { 39 | let fast_mode = if data.5 { 40 | YuvConversionMode::Fast 41 | } else { 42 | YuvConversionMode::Balanced 43 | }; 44 | fuzz_yuv_420(data.0, data.1, data.2, data.3, fast_mode); 45 | fuzz_yuv_422(data.0, data.1, data.2, data.3, fast_mode); 46 | fuzz_yuv_444(data.0, data.1, data.2, data.3, fast_mode); 47 | }); 48 | 49 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u8, uv_value: u8, mode: YuvConversionMode) { 50 | if i_height == 0 || i_width == 0 { 51 | return; 52 | } 53 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 54 | let uv_plane = 55 | vec![uv_value; (i_width as usize).div_ceil(2) * 2 * (i_height as usize).div_ceil(2)]; 56 | 57 | let planar_image = YuvBiPlanarImage { 58 | y_plane: &y_plane, 59 | y_stride: i_width as u32, 60 | uv_plane: &uv_plane, 61 | uv_stride: (i_width as u32).div_ceil(2) * 2, 62 | width: i_width as u32, 63 | height: i_height as u32, 64 | }; 65 | 66 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 67 | 68 | yuv_nv21_to_rgb( 69 | &planar_image, 70 | &mut target_rgb, 71 | i_width as u32 * 3, 72 | YuvRange::Limited, 73 | YuvStandardMatrix::Bt601, 74 | mode, 75 | ) 76 | .unwrap(); 77 | 78 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 79 | 80 | yuv_nv21_to_rgba( 81 | &planar_image, 82 | &mut target_rgba, 83 | i_width as u32 * 4, 84 | YuvRange::Limited, 85 | YuvStandardMatrix::Bt601, 86 | mode, 87 | ) 88 | .unwrap(); 89 | } 90 | 91 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u8, uv_value: u8, mode: YuvConversionMode) { 92 | if i_height == 0 || i_width == 0 { 93 | return; 94 | } 95 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 96 | let uv_plane = vec![uv_value; (i_width as usize).div_ceil(2) * 2 * i_height as usize]; 97 | 98 | let planar_image = YuvBiPlanarImage { 99 | y_plane: &y_plane, 100 | y_stride: i_width as u32, 101 | uv_plane: &uv_plane, 102 | uv_stride: (i_width as u32).div_ceil(2) * 2, 103 | width: i_width as u32, 104 | height: i_height as u32, 105 | }; 106 | 107 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 108 | 109 | yuv_nv16_to_rgb( 110 | &planar_image, 111 | &mut target_rgb, 112 | i_width as u32 * 3, 113 | YuvRange::Limited, 114 | YuvStandardMatrix::Bt601, 115 | mode, 116 | ) 117 | .unwrap(); 118 | 119 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 120 | 121 | yuv_nv16_to_rgba( 122 | &planar_image, 123 | &mut target_rgba, 124 | i_width as u32 * 4, 125 | YuvRange::Limited, 126 | YuvStandardMatrix::Bt601, 127 | mode, 128 | ) 129 | .unwrap(); 130 | } 131 | 132 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, uv_value: u8, mode: YuvConversionMode) { 133 | if i_height == 0 || i_width == 0 { 134 | return; 135 | } 136 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 137 | let uv_plane = vec![uv_value; i_width as usize * 2 * i_height as usize]; 138 | 139 | let planar_image = YuvBiPlanarImage { 140 | y_plane: &y_plane, 141 | y_stride: i_width as u32, 142 | uv_plane: &uv_plane, 143 | uv_stride: i_width as u32 * 2, 144 | width: i_width as u32, 145 | height: i_height as u32, 146 | }; 147 | 148 | let mut target_rgb = vec![0u8; i_width as usize * i_height as usize * 3]; 149 | 150 | yuv_nv24_to_rgb( 151 | &planar_image, 152 | &mut target_rgb, 153 | i_width as u32 * 3, 154 | YuvRange::Limited, 155 | YuvStandardMatrix::Bt601, 156 | mode, 157 | ) 158 | .unwrap(); 159 | 160 | let mut target_rgba = vec![0u8; i_width as usize * i_height as usize * 4]; 161 | 162 | yuv_nv24_to_rgba( 163 | &planar_image, 164 | &mut target_rgba, 165 | i_width as u32 * 4, 166 | YuvRange::Limited, 167 | YuvStandardMatrix::Bt601, 168 | mode, 169 | ) 170 | .unwrap(); 171 | } 172 | -------------------------------------------------------------------------------- /fuzz/yuv_to_yuyu2/yuv_to_yuyu2.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #![no_main] 31 | 32 | use libfuzzer_sys::fuzz_target; 33 | use yuv::{ 34 | yuv420_to_yuyv422, yuv422_to_yuyv422, yuv444_to_yuyv422, BufferStoreMut, YuvPackedImageMut, 35 | YuvPlanarImage, 36 | }; 37 | 38 | fuzz_target!(|data: (u8, u8, u8, u8, u8)| { 39 | fuzz_yuv_420(data.0, data.1, data.2, data.3); 40 | fuzz_yuv_422(data.0, data.1, data.2, data.3); 41 | fuzz_yuv_444(data.0, data.1, data.2, data.3); 42 | }); 43 | 44 | fn fuzz_yuv_420(i_width: u8, i_height: u8, y_value: u8, uv_value: u8) { 45 | if i_height == 0 || i_width == 0 { 46 | return; 47 | } 48 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 49 | let u_plane = vec![uv_value; (i_width as usize).div_ceil(2) * (i_height as usize).div_ceil(2)]; 50 | let v_plane = vec![uv_value; (i_width as usize).div_ceil(2) * (i_height as usize).div_ceil(2)]; 51 | 52 | let planar_image = YuvPlanarImage { 53 | y_plane: &y_plane, 54 | y_stride: i_width as u32, 55 | u_plane: &u_plane, 56 | u_stride: (i_width as u32).div_ceil(2), 57 | v_plane: &v_plane, 58 | v_stride: (i_width as u32).div_ceil(2), 59 | width: i_width as u32, 60 | height: i_height as u32, 61 | }; 62 | 63 | let full_size = if i_width % 2 == 0 { 64 | 2 * i_width as usize * i_height as usize 65 | } else { 66 | 2 * (i_width as usize + 1) * i_height as usize 67 | }; 68 | 69 | let yuy2_stride = if i_width % 2 == 0 { 70 | 2 * i_width as usize 71 | } else { 72 | 2 * (i_width as usize + 1) 73 | }; 74 | 75 | let yuy2_plane = vec![0u8; full_size]; 76 | 77 | let mut packed_image = YuvPackedImageMut { 78 | yuy: BufferStoreMut::Owned(yuy2_plane), 79 | yuy_stride: yuy2_stride as u32, 80 | width: i_width as u32, 81 | height: i_height as u32, 82 | }; 83 | 84 | yuv420_to_yuyv422(&mut packed_image, &planar_image).unwrap(); 85 | } 86 | 87 | fn fuzz_yuv_422(i_width: u8, i_height: u8, y_value: u8, uv_value: u8) { 88 | if i_height == 0 || i_width == 0 { 89 | return; 90 | } 91 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 92 | let u_plane = vec![uv_value; (i_width as usize).div_ceil(2) * i_height as usize]; 93 | let v_plane = vec![uv_value; (i_width as usize).div_ceil(2) * i_height as usize]; 94 | 95 | let planar_image = YuvPlanarImage { 96 | y_plane: &y_plane, 97 | y_stride: i_width as u32, 98 | u_plane: &u_plane, 99 | u_stride: (i_width as u32).div_ceil(2), 100 | v_plane: &v_plane, 101 | v_stride: (i_width as u32).div_ceil(2), 102 | width: i_width as u32, 103 | height: i_height as u32, 104 | }; 105 | 106 | let full_size = if i_width % 2 == 0 { 107 | 2 * i_width as usize * i_height as usize 108 | } else { 109 | 2 * (i_width as usize + 1) * i_height as usize 110 | }; 111 | 112 | let yuy2_stride = if i_width % 2 == 0 { 113 | 2 * i_width as usize 114 | } else { 115 | 2 * (i_width as usize + 1) 116 | }; 117 | 118 | let yuy2_plane = vec![0u8; full_size]; 119 | 120 | let mut packed_image = YuvPackedImageMut { 121 | yuy: BufferStoreMut::Owned(yuy2_plane), 122 | yuy_stride: yuy2_stride as u32, 123 | width: i_width as u32, 124 | height: i_height as u32, 125 | }; 126 | 127 | yuv422_to_yuyv422(&mut packed_image, &planar_image).unwrap(); 128 | } 129 | 130 | fn fuzz_yuv_444(i_width: u8, i_height: u8, y_value: u8, uv_value: u8) { 131 | if i_height == 0 || i_width == 0 { 132 | return; 133 | } 134 | let y_plane = vec![y_value; i_height as usize * i_width as usize]; 135 | let u_plane = vec![uv_value; i_width as usize * i_height as usize]; 136 | let v_plane = vec![uv_value; i_width as usize * i_height as usize]; 137 | 138 | let planar_image = YuvPlanarImage { 139 | y_plane: &y_plane, 140 | y_stride: i_width as u32, 141 | u_plane: &u_plane, 142 | u_stride: i_width as u32, 143 | v_plane: &v_plane, 144 | v_stride: i_width as u32, 145 | width: i_width as u32, 146 | height: i_height as u32, 147 | }; 148 | 149 | let full_size = if i_width % 2 == 0 { 150 | 2 * i_width as usize * i_height as usize 151 | } else { 152 | 2 * (i_width as usize + 1) * i_height as usize 153 | }; 154 | 155 | let yuy2_stride = if i_width % 2 == 0 { 156 | 2 * i_width as usize 157 | } else { 158 | 2 * (i_width as usize + 1) 159 | }; 160 | 161 | let yuy2_plane = vec![0u8; full_size]; 162 | 163 | let mut packed_image = YuvPackedImageMut { 164 | yuy: BufferStoreMut::Owned(yuy2_plane), 165 | yuy_stride: yuy2_stride as u32, 166 | width: i_width as u32, 167 | height: i_height as u32, 168 | }; 169 | 170 | yuv444_to_yuyv422(&mut packed_image, &planar_image).unwrap(); 171 | } 172 | -------------------------------------------------------------------------------- /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "nightly" -------------------------------------------------------------------------------- /src/avx2/y_to_rgba.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::avx2::avx2_utils::*; 31 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 32 | #[cfg(target_arch = "x86")] 33 | use std::arch::x86::*; 34 | #[cfg(target_arch = "x86_64")] 35 | use std::arch::x86_64::*; 36 | 37 | pub(crate) fn avx2_y_to_rgba_row( 38 | range: &YuvChromaRange, 39 | transform: &CbCrInverseTransform, 40 | y_plane: &[u8], 41 | rgba: &mut [u8], 42 | start_cx: usize, 43 | width: usize, 44 | ) { 45 | unsafe { 46 | avx2_y_to_rgba_row_impl::( 47 | range, transform, y_plane, rgba, start_cx, width, 48 | ) 49 | } 50 | } 51 | 52 | #[target_feature(enable = "avx2")] 53 | unsafe fn avx2_y_to_rgba_row_impl( 54 | range: &YuvChromaRange, 55 | transform: &CbCrInverseTransform, 56 | y_plane: &[u8], 57 | rgba: &mut [u8], 58 | start_cx: usize, 59 | width: usize, 60 | ) { 61 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 62 | let channels = destination_channels.get_channels_count(); 63 | 64 | let mut cx = start_cx; 65 | let y_ptr = y_plane.as_ptr(); 66 | let rgba_ptr = rgba.as_mut_ptr(); 67 | 68 | let y_corr = _mm256_set1_epi8(range.bias_y as i8); 69 | let v_luma_coeff = _mm256_set1_epi16(transform.y_coef as i16); 70 | 71 | while cx + 64 < width { 72 | let yvl0 = _mm256_loadu_si256(y_ptr.add(cx) as *const __m256i); 73 | let yvl1 = _mm256_loadu_si256(y_ptr.add(cx + 32) as *const __m256i); 74 | 75 | let y_values0 = _mm256_subs_epu8(yvl0, y_corr); 76 | let y_values1 = _mm256_subs_epu8(yvl1, y_corr); 77 | 78 | let y0 = _mm256_expand8_unordered_to_10(y_values0); 79 | let y1 = _mm256_expand8_unordered_to_10(y_values1); 80 | 81 | let y_high0 = _mm256_mulhrs_epi16(y0.1, v_luma_coeff); 82 | let y_high1 = _mm256_mulhrs_epi16(y1.1, v_luma_coeff); 83 | let y_low0 = _mm256_mulhrs_epi16(y0.0, v_luma_coeff); 84 | let y_low1 = _mm256_mulhrs_epi16(y1.0, v_luma_coeff); 85 | 86 | let v_values0 = _mm256_packus_epi16(y_low0, y_high0); 87 | let v_values1 = _mm256_packus_epi16(y_low1, y_high1); 88 | 89 | let dst_shift = cx * channels; 90 | 91 | let v_alpha = _mm256_set1_epi8(255u8 as i8); 92 | _mm256_store_interleave_rgb_for_yuv::( 93 | rgba_ptr.add(dst_shift), 94 | v_values0, 95 | v_values0, 96 | v_values0, 97 | v_alpha, 98 | ); 99 | 100 | _mm256_store_interleave_rgb_for_yuv::( 101 | rgba_ptr.add(dst_shift + channels * 32), 102 | v_values1, 103 | v_values1, 104 | v_values1, 105 | v_alpha, 106 | ); 107 | 108 | cx += 64; 109 | } 110 | 111 | while cx + 32 < width { 112 | let y_values = 113 | _mm256_subs_epu8(_mm256_loadu_si256(y_ptr.add(cx) as *const __m256i), y_corr); 114 | 115 | let y0 = _mm256_expand8_unordered_to_10(y_values); 116 | 117 | let y_high = _mm256_mulhrs_epi16(y0.1, v_luma_coeff); 118 | 119 | let y_low = _mm256_mulhrs_epi16(y0.0, v_luma_coeff); 120 | 121 | let v_values = _mm256_packus_epi16(y_low, y_high); 122 | 123 | let dst_shift = cx * channels; 124 | 125 | let v_alpha = _mm256_set1_epi8(255u8 as i8); 126 | _mm256_store_interleave_rgb_for_yuv::( 127 | rgba_ptr.add(dst_shift), 128 | v_values, 129 | v_values, 130 | v_values, 131 | v_alpha, 132 | ); 133 | 134 | cx += 32; 135 | } 136 | 137 | if cx < width { 138 | let diff = width - cx; 139 | assert!(diff <= 32); 140 | 141 | let mut y_buffer: [u8; 32] = [0; 32]; 142 | let mut dst_buffer: [u8; 32 * 4] = [0; 32 * 4]; 143 | std::ptr::copy_nonoverlapping( 144 | y_plane.get_unchecked(cx..).as_ptr(), 145 | y_buffer.as_mut_ptr(), 146 | diff, 147 | ); 148 | 149 | let y_values = _mm256_subs_epu8( 150 | _mm256_loadu_si256(y_buffer.as_ptr() as *const __m256i), 151 | y_corr, 152 | ); 153 | 154 | let y0 = _mm256_expand8_unordered_to_10(y_values); 155 | 156 | let y_high = _mm256_mulhrs_epi16(y0.1, v_luma_coeff); 157 | 158 | let y_low = _mm256_mulhrs_epi16(y0.0, v_luma_coeff); 159 | 160 | let v_values = _mm256_packus_epi16(y_low, y_high); 161 | 162 | let v_alpha = _mm256_set1_epi8(255u8 as i8); 163 | _mm256_store_interleave_rgb_for_yuv::( 164 | dst_buffer.as_mut_ptr(), 165 | v_values, 166 | v_values, 167 | v_values, 168 | v_alpha, 169 | ); 170 | 171 | let dst_shift = cx * channels; 172 | 173 | std::ptr::copy_nonoverlapping( 174 | dst_buffer.as_ptr(), 175 | rgba_ptr.add(dst_shift), 176 | diff * channels, 177 | ); 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/avx2/y_to_rgba_alpha.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::avx2::avx2_utils::*; 31 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 32 | #[cfg(target_arch = "x86")] 33 | use std::arch::x86::*; 34 | #[cfg(target_arch = "x86_64")] 35 | use std::arch::x86_64::*; 36 | 37 | pub(crate) fn avx2_y_to_rgba_alpha_row( 38 | range: &YuvChromaRange, 39 | transform: &CbCrInverseTransform, 40 | y_plane: &[u8], 41 | a_plane: &[u8], 42 | rgba: &mut [u8], 43 | start_cx: usize, 44 | width: usize, 45 | ) -> usize { 46 | unsafe { 47 | avx2_y_to_rgba_alpha_row_impl::( 48 | range, transform, y_plane, a_plane, rgba, start_cx, width, 49 | ) 50 | } 51 | } 52 | 53 | #[target_feature(enable = "avx2")] 54 | unsafe fn avx2_y_to_rgba_alpha_row_impl( 55 | range: &YuvChromaRange, 56 | transform: &CbCrInverseTransform, 57 | y_plane: &[u8], 58 | a_plane: &[u8], 59 | rgba: &mut [u8], 60 | start_cx: usize, 61 | width: usize, 62 | ) -> usize { 63 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 64 | let channels = destination_channels.get_channels_count(); 65 | 66 | let mut cx = start_cx; 67 | let y_ptr = y_plane.as_ptr(); 68 | let rgba_ptr = rgba.as_mut_ptr(); 69 | 70 | let y_corr = _mm256_set1_epi8(range.bias_y as i8); 71 | let v_luma_coeff = _mm256_set1_epi16(transform.y_coef as i16); 72 | 73 | while cx + 64 < width { 74 | let yvl0 = _mm256_loadu_si256(y_ptr.add(cx) as *const __m256i); 75 | let yvl1 = _mm256_loadu_si256(y_ptr.add(cx + 32) as *const __m256i); 76 | let a_values0 = _mm256_loadu_si256(a_plane.get_unchecked(cx..).as_ptr() as *const __m256i); 77 | let a_values1 = 78 | _mm256_loadu_si256(a_plane.get_unchecked((cx + 32)..).as_ptr() as *const __m256i); 79 | 80 | let y_values0 = _mm256_subs_epu8(yvl0, y_corr); 81 | let y_values1 = _mm256_subs_epu8(yvl1, y_corr); 82 | 83 | let y0 = _mm256_expand8_unordered_to_10(y_values0); 84 | let y1 = _mm256_expand8_unordered_to_10(y_values1); 85 | 86 | let y_high0 = _mm256_mulhrs_epi16(y0.1, v_luma_coeff); 87 | let y_high1 = _mm256_mulhrs_epi16(y1.1, v_luma_coeff); 88 | let y_low0 = _mm256_mulhrs_epi16(y0.0, v_luma_coeff); 89 | let y_low1 = _mm256_mulhrs_epi16(y1.0, v_luma_coeff); 90 | 91 | let v_values0 = _mm256_packus_epi16(y_low0, y_high0); 92 | let v_values1 = _mm256_packus_epi16(y_low1, y_high1); 93 | 94 | let dst_shift = cx * channels; 95 | 96 | _mm256_store_interleave_rgb_for_yuv::( 97 | rgba_ptr.add(dst_shift), 98 | v_values0, 99 | v_values0, 100 | v_values0, 101 | a_values0, 102 | ); 103 | 104 | _mm256_store_interleave_rgb_for_yuv::( 105 | rgba_ptr.add(dst_shift + channels * 32), 106 | v_values1, 107 | v_values1, 108 | v_values1, 109 | a_values1, 110 | ); 111 | 112 | cx += 64; 113 | } 114 | 115 | while cx + 32 < width { 116 | let y_values = 117 | _mm256_subs_epu8(_mm256_loadu_si256(y_ptr.add(cx) as *const __m256i), y_corr); 118 | 119 | let a_values = _mm256_loadu_si256(a_plane.get_unchecked(cx..).as_ptr() as *const __m256i); 120 | 121 | let y0 = _mm256_expand8_unordered_to_10(y_values); 122 | 123 | let y_high = _mm256_mulhrs_epi16(y0.1, v_luma_coeff); 124 | 125 | let y_low = _mm256_mulhrs_epi16(y0.0, v_luma_coeff); 126 | 127 | let v_values = _mm256_packus_epi16(y_low, y_high); 128 | 129 | let dst_shift = cx * channels; 130 | 131 | _mm256_store_interleave_rgb_for_yuv::( 132 | rgba_ptr.add(dst_shift), 133 | v_values, 134 | v_values, 135 | v_values, 136 | a_values, 137 | ); 138 | 139 | cx += 32; 140 | } 141 | 142 | while cx + 16 < width { 143 | let y_values = _mm256_subs_epu8( 144 | _mm256_castsi128_si256(_mm_loadu_si128(y_ptr.add(cx) as *const __m128i)), 145 | y_corr, 146 | ); 147 | let a_values = _mm_loadu_si128(a_plane.get_unchecked(cx..).as_ptr() as *const __m128i); 148 | 149 | let y0 = _mm256_expand8_unordered_to_10(_mm256_permute4x64_epi64::<0x50>(y_values)); 150 | let y_low = _mm256_mulhrs_epi16(y0.0, v_luma_coeff); 151 | 152 | let v_values = avx2_pack_u16(y_low, _mm256_setzero_si256()); 153 | 154 | let dst_shift = cx * channels; 155 | 156 | _mm256_store_interleave_rgb_half_for_yuv::( 157 | rgba_ptr.add(dst_shift), 158 | v_values, 159 | v_values, 160 | v_values, 161 | _mm256_castsi128_si256(a_values), 162 | ); 163 | 164 | cx += 16; 165 | } 166 | 167 | cx 168 | } 169 | -------------------------------------------------------------------------------- /src/avx2/yuv_to_yuv2.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::avx2::avx2_utils::{ 30 | _mm256_deinterleave_x2_epi8, _mm256_havg_epu8, _mm256_store_interleaved_epi8, 31 | }; 32 | use crate::yuv_support::{YuvChromaSubsampling, Yuy2Description}; 33 | use crate::yuv_to_yuy2::YuvToYuy2Navigation; 34 | #[cfg(target_arch = "x86")] 35 | use std::arch::x86::*; 36 | #[cfg(target_arch = "x86_64")] 37 | use std::arch::x86_64::*; 38 | 39 | pub(crate) fn yuv_to_yuy2_avx2_row( 40 | y_plane: &[u8], 41 | u_plane: &[u8], 42 | v_plane: &[u8], 43 | yuy2_store: &mut [u8], 44 | width: u32, 45 | nav: YuvToYuy2Navigation, 46 | ) -> YuvToYuy2Navigation { 47 | unsafe { 48 | yuv_to_yuy2_avx2_row_impl::( 49 | y_plane, u_plane, v_plane, yuy2_store, width, nav, 50 | ) 51 | } 52 | } 53 | 54 | #[target_feature(enable = "avx2")] 55 | pub(crate) unsafe fn yuv_to_yuy2_avx2_row_impl( 56 | y_plane: &[u8], 57 | u_plane: &[u8], 58 | v_plane: &[u8], 59 | yuy2_store: &mut [u8], 60 | width: u32, 61 | nav: YuvToYuy2Navigation, 62 | ) -> YuvToYuy2Navigation { 63 | let yuy2_target: Yuy2Description = YUY2_TARGET.into(); 64 | let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into(); 65 | 66 | let mut _cx = nav.cx; 67 | let mut _uv_x = nav.uv_x; 68 | let mut _yuy2_x = nav.x; 69 | let chroma_big_step = match chroma_subsampling { 70 | YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => 32, 71 | YuvChromaSubsampling::Yuv444 => 64, 72 | }; 73 | unsafe { 74 | while _cx + 64 < width as usize { 75 | let u_pos = _uv_x; 76 | let v_pos = _uv_x; 77 | let y_pos = _cx; 78 | 79 | let u_pixels; 80 | let v_pixels; 81 | 82 | let y_ptr = y_plane.as_ptr().add(y_pos); 83 | let y_pixels = ( 84 | _mm256_loadu_si256(y_ptr as *const __m256i), 85 | _mm256_loadu_si256(y_ptr.add(32) as *const __m256i), 86 | ); 87 | 88 | if chroma_subsampling == YuvChromaSubsampling::Yuv444 { 89 | let u_ptr = u_plane.as_ptr().add(u_pos); 90 | let full_u = ( 91 | _mm256_loadu_si256(u_ptr as *const __m256i), 92 | _mm256_loadu_si256(u_ptr.add(32) as *const __m256i), 93 | ); 94 | let v_ptr = v_plane.as_ptr().add(v_pos); 95 | let full_v = ( 96 | _mm256_loadu_si256(v_ptr as *const __m256i), 97 | _mm256_loadu_si256(v_ptr.add(32) as *const __m256i), 98 | ); 99 | 100 | u_pixels = _mm256_havg_epu8(full_u.0, full_u.1); 101 | v_pixels = _mm256_havg_epu8(full_v.0, full_v.1); 102 | } else { 103 | u_pixels = _mm256_loadu_si256(u_plane.as_ptr().add(u_pos) as *const __m256i); 104 | v_pixels = _mm256_loadu_si256(v_plane.as_ptr().add(v_pos) as *const __m256i); 105 | } 106 | 107 | let (low_y, high_y) = _mm256_deinterleave_x2_epi8(y_pixels.0, y_pixels.1); 108 | 109 | let storage = match yuy2_target { 110 | Yuy2Description::YUYV => (low_y, u_pixels, high_y, v_pixels), 111 | Yuy2Description::UYVY => (u_pixels, low_y, v_pixels, high_y), 112 | Yuy2Description::YVYU => (low_y, v_pixels, high_y, u_pixels), 113 | Yuy2Description::VYUY => (v_pixels, low_y, u_pixels, high_y), 114 | }; 115 | 116 | let dst_offset = _cx * 2; 117 | 118 | _mm256_store_interleaved_epi8( 119 | yuy2_store.as_mut_ptr().add(dst_offset), 120 | storage.0, 121 | storage.1, 122 | storage.2, 123 | storage.3, 124 | ); 125 | 126 | _uv_x += chroma_big_step; 127 | _cx += 64; 128 | } 129 | 130 | _yuy2_x = _cx; 131 | 132 | YuvToYuy2Navigation { 133 | cx: _cx, 134 | uv_x: _uv_x, 135 | x: _yuy2_x, 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/avx2/yuy2_to_yuv.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::avx2::avx2_utils::{ 30 | _mm256_deinterleave_rgba_epi8, _mm256_interleave_epi8, _mm256_interleave_x2_epi8, 31 | }; 32 | use crate::yuv_support::{YuvChromaSubsampling, Yuy2Description}; 33 | use crate::yuv_to_yuy2::YuvToYuy2Navigation; 34 | #[cfg(target_arch = "x86")] 35 | use std::arch::x86::*; 36 | #[cfg(target_arch = "x86_64")] 37 | use std::arch::x86_64::*; 38 | 39 | pub(crate) fn yuy2_to_yuv_avx( 40 | y_plane: &mut [u8], 41 | u_plane: &mut [u8], 42 | v_plane: &mut [u8], 43 | yuy2_store: &[u8], 44 | width: u32, 45 | nav: YuvToYuy2Navigation, 46 | ) -> YuvToYuy2Navigation { 47 | unsafe { 48 | yuy2_to_yuv_avx_impl::( 49 | y_plane, u_plane, v_plane, yuy2_store, width, nav, 50 | ) 51 | } 52 | } 53 | 54 | #[target_feature(enable = "avx2")] 55 | unsafe fn yuy2_to_yuv_avx_impl( 56 | y_plane: &mut [u8], 57 | u_plane: &mut [u8], 58 | v_plane: &mut [u8], 59 | yuy2_store: &[u8], 60 | width: u32, 61 | nav: YuvToYuy2Navigation, 62 | ) -> YuvToYuy2Navigation { 63 | let yuy2_source: Yuy2Description = YUY2_TARGET.into(); 64 | let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into(); 65 | 66 | let mut _cx = nav.cx; 67 | let mut _uv_x = nav.uv_x; 68 | let mut _yuy2_x = nav.x; 69 | 70 | while _cx + 64 < width as usize { 71 | let dst_offset = _cx * 2; 72 | let u_pos = _uv_x; 73 | let v_pos = _uv_x; 74 | let y_pos = _cx; 75 | 76 | let yuy2_ptr = yuy2_store.as_ptr().add(dst_offset); 77 | 78 | let j0 = _mm256_loadu_si256(yuy2_ptr as *const __m256i); 79 | let j1 = _mm256_loadu_si256(yuy2_ptr.add(32) as *const __m256i); 80 | let j2 = _mm256_loadu_si256(yuy2_ptr.add(64) as *const __m256i); 81 | let j3 = _mm256_loadu_si256(yuy2_ptr.add(96) as *const __m256i); 82 | 83 | let pixel_set = _mm256_deinterleave_rgba_epi8(j0, j1, j2, j3); 84 | let mut y_first = match yuy2_source { 85 | Yuy2Description::YUYV | Yuy2Description::YVYU => pixel_set.0, 86 | Yuy2Description::UYVY | Yuy2Description::VYUY => pixel_set.1, 87 | }; 88 | let mut y_second = match yuy2_source { 89 | Yuy2Description::YUYV | Yuy2Description::YVYU => pixel_set.2, 90 | Yuy2Description::UYVY | Yuy2Description::VYUY => pixel_set.3, 91 | }; 92 | 93 | (y_first, y_second) = _mm256_interleave_epi8(y_first, y_second); 94 | 95 | let u_value = match yuy2_source { 96 | Yuy2Description::YUYV => pixel_set.1, 97 | Yuy2Description::UYVY => pixel_set.0, 98 | Yuy2Description::YVYU => pixel_set.3, 99 | Yuy2Description::VYUY => pixel_set.2, 100 | }; 101 | let v_value = match yuy2_source { 102 | Yuy2Description::YUYV => pixel_set.3, 103 | Yuy2Description::UYVY => pixel_set.2, 104 | Yuy2Description::YVYU => pixel_set.1, 105 | Yuy2Description::VYUY => pixel_set.0, 106 | }; 107 | 108 | if chroma_subsampling == YuvChromaSubsampling::Yuv444 { 109 | let (low_u_value, high_u_value) = _mm256_interleave_x2_epi8(u_value, u_value); 110 | let (low_v_value, high_v_value) = _mm256_interleave_x2_epi8(v_value, v_value); 111 | 112 | let u_plane_ptr = u_plane.as_mut_ptr().add(u_pos); 113 | let v_plane_ptr = v_plane.as_mut_ptr().add(v_pos); 114 | 115 | _mm256_storeu_si256(u_plane_ptr as *mut __m256i, low_u_value); 116 | _mm256_storeu_si256(u_plane_ptr.add(32) as *mut __m256i, high_u_value); 117 | _mm256_storeu_si256(v_plane_ptr as *mut __m256i, low_v_value); 118 | _mm256_storeu_si256(v_plane_ptr.add(32) as *mut __m256i, high_v_value); 119 | } else { 120 | _mm256_storeu_si256(u_plane.as_mut_ptr().add(u_pos) as *mut __m256i, u_value); 121 | _mm256_storeu_si256(v_plane.as_mut_ptr().add(v_pos) as *mut __m256i, v_value); 122 | } 123 | 124 | let y_plane_ptr = y_plane.as_mut_ptr().add(y_pos); 125 | 126 | _mm256_storeu_si256(y_plane_ptr as *mut __m256i, y_first); 127 | _mm256_storeu_si256(y_plane_ptr.add(32) as *mut __m256i, y_second); 128 | 129 | _uv_x += match chroma_subsampling { 130 | YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => 32, 131 | YuvChromaSubsampling::Yuv444 => 64, 132 | }; 133 | _cx += 64; 134 | } 135 | 136 | _yuy2_x = _cx; 137 | 138 | YuvToYuy2Navigation { 139 | cx: _cx, 140 | uv_x: _uv_x, 141 | x: _yuy2_x, 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/avx512bw/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #![deny(unreachable_code, unreachable_pub)] 30 | mod avx512_setr; 31 | mod avx512_utils; 32 | mod rgb_to_nv420; 33 | #[cfg(feature = "professional_mode")] 34 | mod rgb_to_nv420_prof; 35 | mod rgb_to_y; 36 | mod rgb_to_yuv_p16; 37 | mod rgb_to_yuv_p16_420; 38 | mod rgba_to_yuv; 39 | mod rgba_to_yuv420; 40 | #[cfg(feature = "fast_mode")] 41 | mod rgba_to_yuv_fast; 42 | #[cfg(feature = "fast_mode")] 43 | mod rgba_to_yuv_fast420; 44 | mod y_to_rgb; 45 | mod yuv_nv_to_rgba; 46 | mod yuv_nv_to_rgba420; 47 | mod yuv_nv_to_rgba422; 48 | #[cfg(feature = "fast_mode")] 49 | mod yuv_nv_to_rgba_fast420; 50 | mod yuv_p16_to_rgb16; 51 | mod yuv_p16_to_rgb8; 52 | mod yuv_to_rgba; 53 | mod yuv_to_rgba420; 54 | mod yuv_to_rgba422; 55 | mod yuv_to_rgba_alpha; 56 | 57 | pub(crate) use rgb_to_nv420::avx512_rgba_to_nv420; 58 | #[cfg(feature = "professional_mode")] 59 | pub(crate) use rgb_to_nv420_prof::avx512_rgba_to_nv420_prof; 60 | pub(crate) use rgb_to_y::avx512_row_rgb_to_y; 61 | pub(crate) use rgb_to_yuv_p16::avx512_rgba_to_yuv_p16; 62 | pub(crate) use rgb_to_yuv_p16_420::avx512_rgba_to_yuv_p16_420; 63 | pub(crate) use rgba_to_yuv::avx512_rgba_to_yuv; 64 | pub(crate) use rgba_to_yuv420::avx512_rgba_to_yuv420; 65 | #[cfg(feature = "fast_mode")] 66 | pub(crate) use rgba_to_yuv_fast::{avx512_rgba_to_yuv_dot_rgba, avx512_rgba_to_yuv_dot_rgba_bmi}; 67 | #[cfg(feature = "fast_mode")] 68 | pub(crate) use rgba_to_yuv_fast420::{ 69 | avx512_rgba_to_yuv_dot_rgba420, avx512_rgba_to_yuv_dot_rgba420_vbmi, 70 | }; 71 | pub(crate) use y_to_rgb::avx512_y_to_rgb_row; 72 | pub(crate) use yuv_nv_to_rgba::avx512_yuv_nv_to_rgba; 73 | pub(crate) use yuv_nv_to_rgba420::avx512_yuv_nv_to_rgba420; 74 | pub(crate) use yuv_nv_to_rgba422::avx512_yuv_nv_to_rgba422; 75 | #[cfg(feature = "fast_mode")] 76 | pub(crate) use yuv_nv_to_rgba_fast420::avx512_yuv_nv_to_rgba_fast420; 77 | pub(crate) use yuv_p16_to_rgb16::avx512_yuv_p16_to_rgba16_row; 78 | pub(crate) use yuv_p16_to_rgb8::avx512_yuv_p16_to_rgba8_row; 79 | pub(crate) use yuv_to_rgba::avx512_yuv_to_rgba; 80 | pub(crate) use yuv_to_rgba420::avx512_yuv_to_rgba420; 81 | pub(crate) use yuv_to_rgba422::avx512_yuv_to_rgba422; 82 | pub(crate) use yuv_to_rgba_alpha::avx512_yuv_to_rgba_alpha; 83 | -------------------------------------------------------------------------------- /src/avx512bw/y_to_rgb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::avx512bw::avx512_utils::{_mm512_expand8_unordered_to_10, avx512_store_rgba_for_yuv_u8}; 31 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 32 | #[cfg(target_arch = "x86")] 33 | use std::arch::x86::*; 34 | #[cfg(target_arch = "x86_64")] 35 | use std::arch::x86_64::*; 36 | 37 | pub(crate) fn avx512_y_to_rgb_row( 38 | range: &YuvChromaRange, 39 | transform: &CbCrInverseTransform, 40 | y_plane: &[u8], 41 | rgba: &mut [u8], 42 | start_cx: usize, 43 | width: usize, 44 | ) { 45 | unsafe { 46 | if HAS_VBMI { 47 | avx512_y_to_rgb_bmi_row::( 48 | range, transform, y_plane, rgba, start_cx, width, 49 | ) 50 | } else { 51 | avx512_y_to_rgb_def_row::( 52 | range, transform, y_plane, rgba, start_cx, width, 53 | ) 54 | } 55 | } 56 | } 57 | 58 | #[target_feature(enable = "avx512bw", enable = "avx512f")] 59 | unsafe fn avx512_y_to_rgb_def_row( 60 | range: &YuvChromaRange, 61 | transform: &CbCrInverseTransform, 62 | y_plane: &[u8], 63 | rgba: &mut [u8], 64 | start_cx: usize, 65 | width: usize, 66 | ) { 67 | avx512_y_to_rgb_row_impl::( 68 | range, transform, y_plane, rgba, start_cx, width, 69 | ) 70 | } 71 | 72 | #[target_feature(enable = "avx512bw", enable = "avx512f", enable = "avx512vbmi")] 73 | unsafe fn avx512_y_to_rgb_bmi_row( 74 | range: &YuvChromaRange, 75 | transform: &CbCrInverseTransform, 76 | y_plane: &[u8], 77 | rgba: &mut [u8], 78 | start_cx: usize, 79 | width: usize, 80 | ) { 81 | avx512_y_to_rgb_row_impl::( 82 | range, transform, y_plane, rgba, start_cx, width, 83 | ) 84 | } 85 | 86 | #[inline(always)] 87 | unsafe fn avx512_y_to_rgb_row_impl( 88 | range: &YuvChromaRange, 89 | transform: &CbCrInverseTransform, 90 | y_plane: &[u8], 91 | rgba: &mut [u8], 92 | start_cx: usize, 93 | width: usize, 94 | ) { 95 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 96 | let channels = destination_channels.get_channels_count(); 97 | 98 | let mut cx = start_cx; 99 | let y_ptr = y_plane.as_ptr(); 100 | let rgba_ptr = rgba.as_mut_ptr(); 101 | 102 | let y_corr = _mm512_set1_epi8(range.bias_y as i8); 103 | let v_luma_coeff = _mm512_set1_epi16(transform.y_coef as i16); 104 | let v_alpha = _mm512_set1_epi8(255u8 as i8); 105 | 106 | while cx + 64 < width { 107 | let y_s = _mm512_subs_epi8(_mm512_loadu_si512(y_ptr.add(cx) as *const _), y_corr); 108 | 109 | let y10 = _mm512_expand8_unordered_to_10(y_s); 110 | 111 | let y_high = _mm512_mulhrs_epi16(y10.1, v_luma_coeff); 112 | 113 | let r_high = y_high; 114 | 115 | let y_low = _mm512_mulhrs_epi16(y10.0, v_luma_coeff); 116 | 117 | let r_low = y_low; 118 | 119 | let r_values = _mm512_packus_epi16(r_low, r_high); 120 | 121 | let dst_shift = cx * channels; 122 | 123 | avx512_store_rgba_for_yuv_u8::( 124 | rgba_ptr.add(dst_shift), 125 | r_values, 126 | r_values, 127 | r_values, 128 | v_alpha, 129 | ); 130 | 131 | cx += 64; 132 | } 133 | 134 | if cx < width { 135 | let diff = width - cx; 136 | assert!(diff <= 64); 137 | 138 | let mut y_buffer: [u8; 64] = [0; 64]; 139 | let mut dst_buffer: [u8; 64 * 4] = [0; 64 * 4]; 140 | std::ptr::copy_nonoverlapping( 141 | y_plane.get_unchecked(cx..).as_ptr(), 142 | y_buffer.as_mut_ptr(), 143 | diff, 144 | ); 145 | 146 | let y_s = _mm512_subs_epi8(_mm512_loadu_si512(y_buffer.as_ptr() as *const _), y_corr); 147 | 148 | let y10 = _mm512_expand8_unordered_to_10(y_s); 149 | 150 | let y_high = _mm512_mulhrs_epi16(y10.1, v_luma_coeff); 151 | 152 | let r_high = y_high; 153 | 154 | let y_low = _mm512_mulhrs_epi16(y10.0, v_luma_coeff); 155 | 156 | let r_low = y_low; 157 | 158 | let r_values = _mm512_packus_epi16(r_low, r_high); 159 | 160 | avx512_store_rgba_for_yuv_u8::( 161 | dst_buffer.as_mut_ptr(), 162 | r_values, 163 | r_values, 164 | r_values, 165 | v_alpha, 166 | ); 167 | 168 | let dst_shift = cx * channels; 169 | 170 | std::ptr::copy_nonoverlapping( 171 | dst_buffer.as_ptr(), 172 | rgba_ptr.add(dst_shift), 173 | diff * channels, 174 | ); 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/internals.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::yuv_support::{CbCrForwardTransform, CbCrInverseTransform, YuvChromaRange}; 30 | 31 | #[allow(dead_code)] 32 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] 33 | pub(crate) struct ProcessedOffset { 34 | pub(crate) cx: usize, 35 | pub(crate) ux: usize, 36 | } 37 | 38 | pub(crate) trait WideRowInversionHandler { 39 | fn handle_row( 40 | &self, 41 | y_plane: &[V], 42 | u_plane: &[V], 43 | v_plane: &[V], 44 | rgba: &mut [V], 45 | width: u32, 46 | chroma: YuvChromaRange, 47 | transform: &CbCrInverseTransform, 48 | ) -> ProcessedOffset; 49 | } 50 | 51 | pub(crate) trait WideRowAlphaInversionHandler { 52 | fn handle_row( 53 | &self, 54 | y_plane: &[V], 55 | u_plane: &[V], 56 | v_plane: &[V], 57 | a_plane: &[V], 58 | rgba: &mut [T], 59 | width: u32, 60 | chroma: YuvChromaRange, 61 | transform: &CbCrInverseTransform, 62 | use_premultiplied_alpha: bool, 63 | ) -> ProcessedOffset; 64 | } 65 | 66 | #[cfg(feature = "nightly_f16")] 67 | pub(crate) trait WideDRowInversionHandler { 68 | fn handle_row( 69 | &self, 70 | y_plane: &[V], 71 | u_plane: &[V], 72 | v_plane: &[V], 73 | rgba: &mut [T], 74 | width: u32, 75 | chroma: YuvChromaRange, 76 | transform: &CbCrInverseTransform, 77 | ) -> ProcessedOffset; 78 | } 79 | 80 | #[cfg(feature = "nightly_f16")] 81 | pub(crate) trait WideDAlphaRowInversionHandler { 82 | fn handle_row( 83 | &self, 84 | y_plane: &[V], 85 | u_plane: &[V], 86 | v_plane: &[V], 87 | a_plane: &[V], 88 | rgba: &mut [T], 89 | width: u32, 90 | chroma: YuvChromaRange, 91 | transform: &CbCrInverseTransform, 92 | ) -> ProcessedOffset; 93 | } 94 | 95 | pub(crate) trait WideRow420InversionHandler { 96 | fn handle_row( 97 | &self, 98 | y0_plane: &[V], 99 | y1_plane: &[V], 100 | u_plane: &[V], 101 | v_plane: &[V], 102 | rgba0: &mut [V], 103 | rgba1: &mut [V], 104 | width: u32, 105 | chroma: YuvChromaRange, 106 | transform: &CbCrInverseTransform, 107 | ) -> ProcessedOffset; 108 | } 109 | 110 | pub(crate) trait RowBiPlanarInversionHandler { 111 | fn handle_row( 112 | &self, 113 | y_plane: &[V], 114 | uv_plane: &[V], 115 | rgba: &mut [V], 116 | width: u32, 117 | chroma: YuvChromaRange, 118 | transform: &CbCrInverseTransform, 119 | ) -> ProcessedOffset; 120 | } 121 | 122 | pub(crate) trait RowDBiPlanarInversionHandler { 123 | fn handle_row( 124 | &self, 125 | y_plane: &[V], 126 | uv_plane: &[V], 127 | rgba: &mut [T], 128 | width: u32, 129 | chroma: YuvChromaRange, 130 | transform: &CbCrInverseTransform, 131 | ) -> ProcessedOffset; 132 | } 133 | 134 | pub(crate) trait RowBiPlanarInversion420Handler { 135 | fn handle_row( 136 | &self, 137 | y_plane0: &[V], 138 | y_plane1: &[V], 139 | uv_plane: &[V], 140 | rgba0: &mut [V], 141 | rgba1: &mut [V], 142 | width: u32, 143 | chroma: YuvChromaRange, 144 | transform: &CbCrInverseTransform, 145 | ) -> ProcessedOffset; 146 | } 147 | 148 | pub(crate) trait WideRowForwardHandler { 149 | fn handle_row( 150 | &self, 151 | y_plane: &mut [V], 152 | u_plane: &mut [V], 153 | v_plane: &mut [V], 154 | rgba: &[V], 155 | width: u32, 156 | chroma: YuvChromaRange, 157 | transform: &CbCrForwardTransform, 158 | ) -> ProcessedOffset; 159 | } 160 | 161 | pub(crate) trait WideRowForward420Handler { 162 | fn handle_row( 163 | &self, 164 | y_plane0: &mut [V], 165 | y_plane1: &mut [V], 166 | u_plane: &mut [V], 167 | v_plane: &mut [V], 168 | rgba0: &[V], 169 | rgba1: &[V], 170 | width: u32, 171 | chroma: YuvChromaRange, 172 | transform: &CbCrForwardTransform, 173 | ) -> ProcessedOffset; 174 | } 175 | 176 | pub(crate) trait WideRowForwardBiPlanar420Handler { 177 | fn handle_rows( 178 | &self, 179 | rgba0: &[V], 180 | rgba1: &[V], 181 | y_plane0: &mut [V], 182 | y_plane1: &mut [V], 183 | uv_plane: &mut [V], 184 | width: u32, 185 | chroma: YuvChromaRange, 186 | transform: &CbCrForwardTransform, 187 | ) -> ProcessedOffset; 188 | } 189 | 190 | pub(crate) trait WideRowForwardBiPlanarHandler { 191 | fn handle_row( 192 | &self, 193 | rgba: &[V], 194 | y_plane: &mut [V], 195 | uv_plane: &mut [V], 196 | width: u32, 197 | chroma: YuvChromaRange, 198 | transform: &CbCrForwardTransform, 199 | ) -> ProcessedOffset; 200 | } 201 | -------------------------------------------------------------------------------- /src/neon/ar30_utils.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 1/2025. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::yuv_support::Rgb30; 31 | use std::arch::aarch64::*; 32 | 33 | #[inline(always)] 34 | pub(crate) unsafe fn vrev128_u32(v: uint32x4_t) -> uint32x4_t { 35 | vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(v))) 36 | } 37 | 38 | #[inline(always)] 39 | pub(crate) unsafe fn vzipq_4_ar30( 40 | v: uint16x8x3_t, 41 | ) -> uint32x4x2_t { 42 | let ar_type: Rgb30 = AR30_TYPE.into(); 43 | match ar_type { 44 | Rgb30::Ar30 | Rgb30::Ab30 => { 45 | let mut a0 = vdupq_n_u32(3); 46 | let mut a1 = vdupq_n_u32(3); 47 | 48 | let mut rw0 = vmovl_u16(vget_low_u16(v.2)); 49 | let mut rw1 = vmovl_u16(vget_high_u16(v.2)); 50 | let gw0 = vmovl_u16(vget_low_u16(v.1)); 51 | let gw1 = vmovl_u16(vget_high_u16(v.1)); 52 | let mut bw0 = vmovl_u16(vget_low_u16(v.0)); 53 | let mut bw1 = vmovl_u16(vget_high_u16(v.0)); 54 | 55 | if ar_type == Rgb30::Ab30 { 56 | std::mem::swap(&mut rw0, &mut bw0); 57 | std::mem::swap(&mut rw1, &mut bw1); 58 | } 59 | 60 | let r0 = vshlq_n_u32::<20>(rw0); 61 | let r1 = vshlq_n_u32::<20>(rw1); 62 | 63 | let g0 = vshlq_n_u32::<10>(gw0); 64 | let g1 = vshlq_n_u32::<10>(gw1); 65 | 66 | a0 = vorrq_u32(a0, r0); 67 | a1 = vorrq_u32(a1, r1); 68 | 69 | a0 = vorrq_u32(a0, g0); 70 | a1 = vorrq_u32(a1, g1); 71 | 72 | a0 = vorrq_u32(a0, bw0); 73 | a1 = vorrq_u32(a1, bw1); 74 | 75 | if AR30_ORDER == 0 { 76 | uint32x4x2_t(a0, a1) 77 | } else { 78 | uint32x4x2_t(vrev128_u32(a0), vrev128_u32(a1)) 79 | } 80 | } 81 | Rgb30::Ra30 | Rgb30::Ba30 => { 82 | let mut a0 = vdupq_n_u32(3 << 30); 83 | let mut a1 = vdupq_n_u32(3 << 30); 84 | 85 | let mut rw0 = vmovl_u16(vget_low_u16(v.2)); 86 | let mut rw1 = vmovl_u16(vget_high_u16(v.2)); 87 | let gw0 = vmovl_u16(vget_low_u16(v.1)); 88 | let gw1 = vmovl_u16(vget_high_u16(v.1)); 89 | let mut bw0 = vmovl_u16(vget_low_u16(v.0)); 90 | let mut bw1 = vmovl_u16(vget_high_u16(v.0)); 91 | 92 | if ar_type == Rgb30::Ba30 { 93 | std::mem::swap(&mut rw0, &mut bw0); 94 | std::mem::swap(&mut rw1, &mut bw1); 95 | } 96 | 97 | let r0 = vshlq_n_u32::<22>(rw0); 98 | let r1 = vshlq_n_u32::<22>(rw1); 99 | 100 | a0 = vorrq_u32(a0, r0); 101 | a1 = vorrq_u32(a1, r1); 102 | 103 | let g0 = vshlq_n_u32::<12>(gw0); 104 | let g1 = vshlq_n_u32::<12>(gw1); 105 | 106 | let b0 = vshlq_n_u32::<2>(bw0); 107 | let b1 = vshlq_n_u32::<2>(bw1); 108 | 109 | a0 = vorrq_u32(a0, g0); 110 | a1 = vorrq_u32(a1, g1); 111 | 112 | a0 = vorrq_u32(a0, b0); 113 | a1 = vorrq_u32(a1, b1); 114 | 115 | if AR30_ORDER == 0 { 116 | uint32x4x2_t(a0, a1) 117 | } else { 118 | uint32x4x2_t(vrev128_u32(a0), vrev128_u32(a1)) 119 | } 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/neon/shuffle.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 12/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::neon::utils::{neon_store_half_rgb8, neon_store_rgb8, neon_vld_h_rgb, neon_vld_rgb}; 30 | use crate::shuffle::ShuffleConverter; 31 | use crate::yuv_support::YuvSourceChannels; 32 | 33 | /// This is default shuffling with interleaving and de-interleaving. 34 | /// 35 | pub(crate) struct ShuffleConverterNeon {} 36 | 37 | impl Default for ShuffleConverterNeon { 38 | fn default() -> Self { 39 | ShuffleConverterNeon {} 40 | } 41 | } 42 | 43 | impl ShuffleConverter 44 | for ShuffleConverterNeon 45 | { 46 | fn convert(&self, src: &[u8], dst: &mut [u8], width: usize) { 47 | unsafe { shuffle_channels8_impl::(src, dst, width) } 48 | } 49 | } 50 | 51 | #[inline(always)] 52 | unsafe fn shuffle_channels8_impl( 53 | src: &[u8], 54 | dst: &mut [u8], 55 | _: usize, 56 | ) { 57 | let src_channels: YuvSourceChannels = SRC.into(); 58 | let dst_channels: YuvSourceChannels = DST.into(); 59 | for (src, dst) in src 60 | .chunks_exact(16 * src_channels.get_channels_count()) 61 | .zip(dst.chunks_exact_mut(16 * dst_channels.get_channels_count())) 62 | { 63 | let (a0, b0, c0, d0) = neon_vld_rgb::(src.as_ptr()); 64 | neon_store_rgb8::(dst.as_mut_ptr(), a0, b0, c0, d0); 65 | } 66 | 67 | let src = src 68 | .chunks_exact(16 * src_channels.get_channels_count()) 69 | .remainder(); 70 | let dst = dst 71 | .chunks_exact_mut(16 * dst_channels.get_channels_count()) 72 | .into_remainder(); 73 | 74 | for (src, dst) in src 75 | .chunks_exact(8 * src_channels.get_channels_count()) 76 | .zip(dst.chunks_exact_mut(8 * dst_channels.get_channels_count())) 77 | { 78 | let (a0, b0, c0, d0) = neon_vld_h_rgb::(src.as_ptr()); 79 | neon_store_half_rgb8::(dst.as_mut_ptr(), a0, b0, c0, d0); 80 | } 81 | 82 | let src = src 83 | .chunks_exact(8 * src_channels.get_channels_count()) 84 | .remainder(); 85 | let dst = dst 86 | .chunks_exact_mut(8 * dst_channels.get_channels_count()) 87 | .into_remainder(); 88 | 89 | if !src.is_empty() && !dst.is_empty() { 90 | assert!(src.len() < 64); 91 | assert!(dst.len() < 64); 92 | let mut transient_src: [u8; 64] = [0; 64]; 93 | let mut transient_dst: [u8; 64] = [0; 64]; 94 | std::ptr::copy_nonoverlapping(src.as_ptr(), transient_src.as_mut_ptr(), src.len()); 95 | let (a0, b0, c0, d0) = neon_vld_h_rgb::(transient_src.as_ptr()); 96 | neon_store_half_rgb8::(transient_dst.as_mut_ptr(), a0, b0, c0, d0); 97 | std::ptr::copy_nonoverlapping(transient_dst.as_ptr(), dst.as_mut_ptr(), dst.len()); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/neon/y_p16_to_rgba16.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use std::arch::aarch64::*; 31 | 32 | use crate::internals::ProcessedOffset; 33 | use crate::neon::utils::{neon_store_rgb16, vldq_s16_endian}; 34 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 35 | 36 | pub(crate) unsafe fn neon_y_p16_to_rgba16_row< 37 | const DESTINATION_CHANNELS: u8, 38 | const ENDIANNESS: u8, 39 | const BYTES_POSITION: u8, 40 | const PRECISION: i32, 41 | const BIT_DEPTH: usize, 42 | >( 43 | y_ld_ptr: &[u16], 44 | rgba: &mut [u16], 45 | width: u32, 46 | range: &YuvChromaRange, 47 | transform: &CbCrInverseTransform, 48 | start_cx: usize, 49 | ) -> ProcessedOffset { 50 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 51 | let channels = destination_channels.get_channels_count(); 52 | let dst_ptr = rgba; 53 | 54 | let y_corr = vdupq_n_u16(range.bias_y as u16); 55 | let v_luma_coeff = vdupq_n_u16(transform.y_coef as u16); 56 | let v_alpha = vdupq_n_u16((1 << BIT_DEPTH) - 1); 57 | let v_max_values = vdupq_n_u16((1 << BIT_DEPTH) - 1); 58 | let rnd_base = vdupq_n_u32((1 << (PRECISION - 1)) - 1); 59 | 60 | let mut cx = start_cx; 61 | 62 | while cx + 8 < width as usize { 63 | let y_values = vqsubq_u16( 64 | vreinterpretq_u16_s16(vldq_s16_endian::( 65 | y_ld_ptr.get_unchecked(cx..).as_ptr(), 66 | )), 67 | y_corr, 68 | ); 69 | 70 | let y_high = vmlal_high_u16(rnd_base, y_values, v_luma_coeff); 71 | let y_low = vmlal_u16(rnd_base, vget_low_u16(y_values), vget_low_u16(v_luma_coeff)); 72 | 73 | let r_high = vqshrn_n_u32::(y_high); 74 | let r_low = vqshrn_n_u32::(y_low); 75 | 76 | let r_values = if BIT_DEPTH != 16 { 77 | vminq_u16(vcombine_u16(r_low, r_high), v_max_values) 78 | } else { 79 | vcombine_u16(r_low, r_high) 80 | }; 81 | 82 | neon_store_rgb16::( 83 | dst_ptr.get_unchecked_mut(cx * channels..).as_mut_ptr(), 84 | r_values, 85 | r_values, 86 | r_values, 87 | v_alpha, 88 | ); 89 | 90 | cx += 8; 91 | } 92 | 93 | if cx < width as usize { 94 | let diff = width as usize - cx; 95 | assert!(diff <= 8); 96 | 97 | let mut y_buffer: [u16; 8] = [0; 8]; 98 | let mut dst_buffer: [u16; 8 * 4] = [0; 8 * 4]; 99 | 100 | std::ptr::copy_nonoverlapping( 101 | y_ld_ptr.get_unchecked(cx..).as_ptr(), 102 | y_buffer.as_mut_ptr(), 103 | diff, 104 | ); 105 | 106 | let y_values = vqsubq_u16( 107 | vreinterpretq_u16_s16(vldq_s16_endian::( 108 | y_buffer.as_ptr(), 109 | )), 110 | y_corr, 111 | ); 112 | 113 | let y_high = vmlal_high_u16(rnd_base, y_values, v_luma_coeff); 114 | let y_low = vmlal_u16(rnd_base, vget_low_u16(y_values), vget_low_u16(v_luma_coeff)); 115 | 116 | let r_high = vqshrn_n_u32::(y_high); 117 | let r_low = vqshrn_n_u32::(y_low); 118 | 119 | let r_values = if BIT_DEPTH != 16 { 120 | vminq_u16(vcombine_u16(r_low, r_high), v_max_values) 121 | } else { 122 | vcombine_u16(r_low, r_high) 123 | }; 124 | 125 | neon_store_rgb16::( 126 | dst_buffer.as_mut_ptr(), 127 | r_values, 128 | r_values, 129 | r_values, 130 | v_alpha, 131 | ); 132 | 133 | let dst_shift = cx * channels; 134 | 135 | std::ptr::copy_nonoverlapping( 136 | dst_buffer.as_ptr(), 137 | dst_ptr.get_unchecked_mut(dst_shift..).as_mut_ptr(), 138 | diff * channels, 139 | ); 140 | 141 | cx += diff; 142 | } 143 | 144 | ProcessedOffset { cx, ux: 0 } 145 | } 146 | -------------------------------------------------------------------------------- /src/neon/yuv_to_yuy2.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::neon::utils::xvld1q_u8_x2; 30 | use crate::yuv_support::{YuvChromaSubsampling, Yuy2Description}; 31 | use crate::yuv_to_yuy2::YuvToYuy2Navigation; 32 | use std::arch::aarch64::*; 33 | 34 | pub(crate) fn yuv_to_yuy2_neon_impl( 35 | y_plane: &[u8], 36 | u_plane: &[u8], 37 | v_plane: &[u8], 38 | yuy2_store: &mut [u8], 39 | width: u32, 40 | nav: YuvToYuy2Navigation, 41 | ) -> YuvToYuy2Navigation { 42 | let yuy2_target: Yuy2Description = YUY2_TARGET.into(); 43 | let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into(); 44 | 45 | let shuffle_table: [u8; 16] = [0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15]; 46 | 47 | let chroma_big_step_size = match chroma_subsampling { 48 | YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => 16, 49 | YuvChromaSubsampling::Yuv444 => 32, 50 | }; 51 | 52 | let chroma_small_step_size = match chroma_subsampling { 53 | YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => 8, 54 | YuvChromaSubsampling::Yuv444 => 16, 55 | }; 56 | 57 | let mut cx = nav.cx; 58 | let mut uv_x = nav.uv_x; 59 | unsafe { 60 | let v_shuffle = vld1q_u8(shuffle_table.as_ptr()); 61 | 62 | while cx + 32 < width as usize { 63 | let u_pos = uv_x; 64 | let v_pos = uv_x; 65 | let y_pos = cx; 66 | 67 | let u_pixels; 68 | let v_pixels; 69 | let y_pixels = xvld1q_u8_x2(y_plane.as_ptr().add(y_pos)); 70 | 71 | if chroma_subsampling == YuvChromaSubsampling::Yuv444 { 72 | let full_u = xvld1q_u8_x2(u_plane.as_ptr().add(u_pos)); 73 | let full_v = xvld1q_u8_x2(v_plane.as_ptr().add(v_pos)); 74 | 75 | u_pixels = vrhaddq_u8(full_u.0, full_u.1); 76 | v_pixels = vrhaddq_u8(full_v.0, full_v.1); 77 | } else { 78 | u_pixels = vld1q_u8(u_plane.as_ptr().add(u_pos)); 79 | v_pixels = vld1q_u8(v_plane.as_ptr().add(v_pos)); 80 | } 81 | 82 | let y_pixels_low = vqtbl1q_u8(y_pixels.0, v_shuffle); 83 | let y_pixels_high = vqtbl1q_u8(y_pixels.1, v_shuffle); 84 | 85 | let low_y = vcombine_u8(vget_low_u8(y_pixels_low), vget_low_u8(y_pixels_high)); 86 | let high_y = vcombine_u8(vget_high_u8(y_pixels_low), vget_high_u8(y_pixels_high)); 87 | 88 | let storage = match yuy2_target { 89 | Yuy2Description::YUYV => uint8x16x4_t(low_y, u_pixels, high_y, v_pixels), 90 | Yuy2Description::UYVY => uint8x16x4_t(u_pixels, low_y, v_pixels, high_y), 91 | Yuy2Description::YVYU => uint8x16x4_t(low_y, v_pixels, high_y, u_pixels), 92 | Yuy2Description::VYUY => uint8x16x4_t(v_pixels, low_y, u_pixels, high_y), 93 | }; 94 | 95 | let dst_offset = cx * 2; 96 | 97 | vst4q_u8(yuy2_store.as_mut_ptr().add(dst_offset), storage); 98 | cx += 32; 99 | uv_x += chroma_big_step_size; 100 | } 101 | 102 | while cx + 16 < width as usize { 103 | let u_pos = uv_x; 104 | let v_pos = uv_x; 105 | let y_pos = cx; 106 | 107 | let u_pixels; 108 | let v_pixels; 109 | let mut y_pixels; 110 | 111 | y_pixels = vld1q_u8(y_plane.as_ptr().add(y_pos)); 112 | 113 | if chroma_subsampling == YuvChromaSubsampling::Yuv444 { 114 | let full_u = vld1q_u8(u_plane.as_ptr().add(u_pos)); 115 | let full_v = vld1q_u8(v_plane.as_ptr().add(v_pos)); 116 | 117 | let low_u = vget_low_u8(full_u); 118 | let high_u = vget_high_u8(full_u); 119 | u_pixels = vrhadd_u8(low_u, high_u); 120 | 121 | let low_v = vget_low_u8(full_v); 122 | let high_v = vget_high_u8(full_v); 123 | 124 | v_pixels = vrhadd_u8(low_v, high_v); 125 | } else { 126 | u_pixels = vld1_u8(u_plane.as_ptr().add(u_pos)); 127 | v_pixels = vld1_u8(v_plane.as_ptr().add(v_pos)); 128 | } 129 | 130 | y_pixels = vqtbl1q_u8(y_pixels, v_shuffle); 131 | 132 | let low_y = vget_low_u8(y_pixels); 133 | let high_y = vget_high_u8(y_pixels); 134 | 135 | let storage = match yuy2_target { 136 | Yuy2Description::YUYV => uint8x8x4_t(low_y, u_pixels, high_y, v_pixels), 137 | Yuy2Description::UYVY => uint8x8x4_t(u_pixels, low_y, v_pixels, high_y), 138 | Yuy2Description::YVYU => uint8x8x4_t(low_y, v_pixels, high_y, u_pixels), 139 | Yuy2Description::VYUY => uint8x8x4_t(v_pixels, low_y, u_pixels, high_y), 140 | }; 141 | 142 | let dst_offset = cx * 2; 143 | 144 | vst4_u8(yuy2_store.as_mut_ptr().add(dst_offset), storage); 145 | 146 | cx += 16; 147 | uv_x += chroma_small_step_size; 148 | } 149 | } 150 | 151 | YuvToYuy2Navigation { cx, uv_x, x: cx } 152 | } 153 | -------------------------------------------------------------------------------- /src/numerics.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 11/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #![forbid(unsafe_code)] 30 | use crate::{YuvBytesPacking, YuvEndianness}; 31 | use std::ops::Shr; 32 | 33 | #[inline(always)] 34 | /// Saturating rounding shift right against bit depth 35 | pub(crate) fn qrshr(val: i32) -> i32 { 36 | let rounding: i32 = (1 << (PRECISION - 1)) - 1; 37 | let max_value: i32 = (1 << BIT_DEPTH) - 1; 38 | ((val + rounding) >> PRECISION).min(max_value).max(0) 39 | } 40 | 41 | #[inline] 42 | /// Integer division by 255 with rounding to nearest 43 | pub(crate) fn div_by_255(v: u16) -> u8 { 44 | ((((v + 0x80) >> 8) + v + 0x80) >> 8) as u8 45 | } 46 | 47 | #[inline(always)] 48 | /// Converts to MSB, if needed, and also to big endian 49 | pub(crate) fn to_ne(v: u16, msb: i32) -> u16 { 50 | let endianness: YuvEndianness = ENDIANNESS.into(); 51 | let bytes_position: YuvBytesPacking = BYTES_POSITION.into(); 52 | let new_v = match endianness { 53 | #[cfg(feature = "big_endian")] 54 | YuvEndianness::BigEndian => u16::from_be(v), 55 | YuvEndianness::LittleEndian => u16::from_le(v), 56 | }; 57 | match bytes_position { 58 | YuvBytesPacking::MostSignificantBytes => new_v.shr(msb), 59 | YuvBytesPacking::LeastSignificantBytes => new_v, 60 | } 61 | } 62 | 63 | #[inline(always)] 64 | /// Saturating rounding shift right against bit depth 65 | pub(crate) fn qrshr_n(val: i32, max: i32) -> i32 { 66 | let rounding: i32 = 1 << (PRECISION - 1); 67 | ((val + rounding) >> PRECISION).min(max).max(0) 68 | } 69 | -------------------------------------------------------------------------------- /src/sharpyuv/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #![forbid(unsafe_code)] 30 | #![deny(unreachable_code, unreachable_pub)] 31 | mod sharp_gamma; 32 | mod sharp_rgba_to_yuv; 33 | 34 | pub use sharp_gamma::SharpYuvGammaTransfer; 35 | pub use sharp_rgba_to_yuv::bgr_to_sharp_yuv420; 36 | pub use sharp_rgba_to_yuv::bgr_to_sharp_yuv422; 37 | pub use sharp_rgba_to_yuv::bgra_to_sharp_yuv420; 38 | pub use sharp_rgba_to_yuv::bgra_to_sharp_yuv422; 39 | pub use sharp_rgba_to_yuv::rgb_to_sharp_yuv420; 40 | pub use sharp_rgba_to_yuv::rgb_to_sharp_yuv422; 41 | pub use sharp_rgba_to_yuv::rgba_to_sharp_yuv420; 42 | pub use sharp_rgba_to_yuv::rgba_to_sharp_yuv422; 43 | -------------------------------------------------------------------------------- /src/sharpyuv/sharp_gamma.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #![forbid(unsafe_code)] 30 | #[inline] 31 | /// Linear transfer function for sRGB 32 | pub(crate) fn srgb_to_linear(gamma: f32) -> f32 { 33 | if gamma < 0f32 { 34 | 0f32 35 | } else if gamma < 12.92f32 * 0.003_041_282_5_f32 { 36 | gamma * (1f32 / 12.92f32) 37 | } else if gamma < 1.0f32 { 38 | ((gamma + 0.055_010_717_f32) / 1.055_010_7_f32).powf(2.4f32) 39 | } else { 40 | 1.0f32 41 | } 42 | } 43 | 44 | #[inline] 45 | /// Gamma transfer function for sRGB 46 | pub(crate) fn srgb_from_linear(linear: f32) -> f32 { 47 | if linear < 0.0f32 { 48 | 0.0f32 49 | } else if linear < 0.003_041_282_5_f32 { 50 | linear * 12.92f32 51 | } else if linear < 1.0f32 { 52 | 1.055_010_7_f32 * linear.powf(1.0f32 / 2.4f32) - 0.055_010_717_f32 53 | } else { 54 | 1.0f32 55 | } 56 | } 57 | 58 | #[inline] 59 | /// Linear transfer function for Rec.709 60 | pub(crate) fn rec709_to_linear(gamma: f32) -> f32 { 61 | if gamma < 0.0f32 { 62 | 0.0f32 63 | } else if gamma < 4.5f32 * 0.018_053_97_f32 { 64 | gamma * (1f32 / 4.5f32) 65 | } else if gamma < 1.0f32 { 66 | ((gamma + 0.099_296_82_f32) / 1.099_296_8_f32).powf(1.0f32 / 0.45f32) 67 | } else { 68 | 1.0f32 69 | } 70 | } 71 | 72 | #[inline] 73 | /// Gamma transfer function for Rec.709 74 | pub(crate) fn rec709_from_linear(linear: f32) -> f32 { 75 | if linear < 0.0f32 { 76 | 0.0f32 77 | } else if linear < 0.018_053_97_f32 { 78 | linear * 4.5f32 79 | } else if linear < 1.0f32 { 80 | 1.099_296_8_f32 * linear.powf(0.45f32) - 0.099_296_82_f32 81 | } else { 82 | 1.0f32 83 | } 84 | } 85 | 86 | #[inline(always)] 87 | /// Pure gamma transfer function for gamma 2.2 88 | pub(crate) fn pure_gamma_function(x: f32, gamma: f32) -> f32 { 89 | if x <= 0f32 { 90 | 0f32 91 | } else if x >= 1f32 { 92 | return 1f32; 93 | } else { 94 | return x.powf(gamma); 95 | } 96 | } 97 | 98 | #[inline] 99 | /// Pure gamma transfer function for gamma 2.2 100 | pub(crate) fn gamma2p2_from_linear(linear: f32) -> f32 { 101 | pure_gamma_function(linear, 1f32 / 2.2f32) 102 | } 103 | 104 | #[inline] 105 | /// Linear transfer function for gamma 2.2 106 | pub(crate) fn gamma2p2_to_linear(gamma: f32) -> f32 { 107 | pure_gamma_function(gamma, 2.2f32) 108 | } 109 | 110 | #[inline] 111 | /// Pure gamma transfer function for gamma 2.8 112 | pub(crate) fn gamma2p8_from_linear(linear: f32) -> f32 { 113 | pure_gamma_function(linear, 1f32 / 2.8f32) 114 | } 115 | 116 | #[inline] 117 | /// Linear transfer function for gamma 2.8 118 | pub(crate) fn gamma2p8_to_linear(gamma: f32) -> f32 { 119 | pure_gamma_function(gamma, 2.8f32) 120 | } 121 | 122 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] 123 | /// Declares transfer function for transfer components into a linear colorspace and its inverse 124 | pub enum SharpYuvGammaTransfer { 125 | /// sRGB Transfer function 126 | Srgb, 127 | /// Rec.709 Transfer function 128 | Rec709, 129 | /// Pure gamma 2.2 Transfer function 130 | Gamma2p2, 131 | /// Pure gamma 2.8 Transfer function 132 | Gamma2p8, 133 | } 134 | 135 | impl From for SharpYuvGammaTransfer { 136 | fn from(value: u8) -> Self { 137 | match value { 138 | 0 => SharpYuvGammaTransfer::Srgb, 139 | 1 => SharpYuvGammaTransfer::Rec709, 140 | 2 => SharpYuvGammaTransfer::Gamma2p2, 141 | 3 => SharpYuvGammaTransfer::Gamma2p8, 142 | _ => SharpYuvGammaTransfer::Srgb, 143 | } 144 | } 145 | } 146 | 147 | impl SharpYuvGammaTransfer { 148 | #[inline] 149 | pub fn linearize(&self, value: f32) -> f32 { 150 | match self { 151 | SharpYuvGammaTransfer::Srgb => srgb_to_linear(value), 152 | SharpYuvGammaTransfer::Rec709 => rec709_to_linear(value), 153 | SharpYuvGammaTransfer::Gamma2p2 => gamma2p2_to_linear(value), 154 | SharpYuvGammaTransfer::Gamma2p8 => gamma2p8_to_linear(value), 155 | } 156 | } 157 | 158 | #[inline] 159 | pub fn gamma(&self, value: f32) -> f32 { 160 | match self { 161 | SharpYuvGammaTransfer::Srgb => srgb_from_linear(value), 162 | SharpYuvGammaTransfer::Rec709 => rec709_from_linear(value), 163 | SharpYuvGammaTransfer::Gamma2p2 => gamma2p2_from_linear(value), 164 | SharpYuvGammaTransfer::Gamma2p8 => gamma2p8_from_linear(value), 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/sse/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | #![deny(unreachable_code, unreachable_pub)] 30 | mod gbr_to_rgb; 31 | mod rgb_to_nv; 32 | mod rgb_to_nv420; 33 | #[cfg(feature = "professional_mode")] 34 | mod rgb_to_nv420_prof; 35 | #[cfg(feature = "professional_mode")] 36 | mod rgb_to_nv_prof; 37 | mod rgb_to_y; 38 | #[cfg(feature = "professional_mode")] 39 | mod rgb_to_yuv420_prof; 40 | mod rgb_to_yuv_p16; 41 | mod rgb_to_yuv_p16_420; 42 | #[cfg(feature = "professional_mode")] 43 | mod rgb_to_yuv_prof; 44 | #[cfg(feature = "fast_mode")] 45 | mod rgba_to_nv_fast; 46 | #[cfg(feature = "fast_mode")] 47 | mod rgba_to_nv_fast420; 48 | mod rgba_to_yuv; 49 | mod rgba_to_yuv420; 50 | #[cfg(feature = "fast_mode")] 51 | mod rgba_to_yuv_fast; 52 | #[cfg(feature = "fast_mode")] 53 | mod rgba_to_yuv_fast420; 54 | mod shuffle; 55 | pub(crate) mod utils; 56 | mod y_to_rgba; 57 | mod y_to_rgba_alpha; 58 | mod yuv_nv_p16_to_rgb; 59 | mod yuv_nv_to_rgba; 60 | mod yuv_nv_to_rgba420; 61 | #[cfg(feature = "professional_mode")] 62 | mod yuv_nv_to_rgba420_prof; 63 | mod yuv_nv_to_rgba422; 64 | #[cfg(feature = "fast_mode")] 65 | mod yuv_nv_to_rgba_fast; 66 | #[cfg(feature = "fast_mode")] 67 | mod yuv_nv_to_rgba_fast420; 68 | #[cfg(feature = "professional_mode")] 69 | mod yuv_nv_to_rgba_prof; 70 | mod yuv_p16_to_rgb16; 71 | mod yuv_p16_to_rgb16_alpha; 72 | mod yuv_p16_to_rgb8; 73 | mod yuv_p16_to_rgb8_alpha; 74 | mod yuv_to_rgba; 75 | mod yuv_to_rgba420; 76 | mod yuv_to_rgba422; 77 | mod yuv_to_rgba_alpha; 78 | mod yuv_to_yuy2; 79 | mod yuy2_to_rgb; 80 | mod yuy2_to_yuv; 81 | 82 | pub(crate) use gbr_to_rgb::{sse_yuv_to_rgba_row_full, sse_yuv_to_rgba_row_limited}; 83 | pub(crate) use rgb_to_nv::sse_rgba_to_nv_row; 84 | pub(crate) use rgb_to_nv420::sse_rgba_to_nv_row420; 85 | #[cfg(feature = "professional_mode")] 86 | pub(crate) use rgb_to_nv420_prof::sse_rgba_to_nv420_prof; 87 | #[cfg(feature = "professional_mode")] 88 | pub(crate) use rgb_to_nv_prof::sse_rgba_to_nv_prof; 89 | pub(crate) use rgb_to_y::sse_rgb_to_y; 90 | #[cfg(feature = "professional_mode")] 91 | pub(crate) use rgb_to_yuv420_prof::sse_rgba_to_yuv420_prof; 92 | pub(crate) use rgb_to_yuv_p16::sse_rgba_to_yuv_p16; 93 | pub(crate) use rgb_to_yuv_p16_420::sse_rgba_to_yuv_p16_420; 94 | #[cfg(feature = "professional_mode")] 95 | pub(crate) use rgb_to_yuv_prof::sse_rgba_to_yuv_prof; 96 | #[cfg(feature = "fast_mode")] 97 | pub(crate) use rgba_to_nv_fast::sse_rgba_to_nv_fast_rgba; 98 | #[cfg(feature = "fast_mode")] 99 | pub(crate) use rgba_to_nv_fast420::sse_rgba_to_nv_fast_rgba420; 100 | pub(crate) use rgba_to_yuv::sse_rgba_to_yuv_row; 101 | pub(crate) use rgba_to_yuv420::sse_rgba_to_yuv_row420; 102 | #[cfg(feature = "fast_mode")] 103 | pub(crate) use rgba_to_yuv_fast::sse_rgba_to_yuv_dot_rgba; 104 | #[cfg(feature = "fast_mode")] 105 | pub(crate) use rgba_to_yuv_fast420::sse_rgba_to_yuv_dot_rgba420; 106 | pub(crate) use shuffle::{ShuffleConverterSse, ShuffleQTableConverterSse}; 107 | pub(crate) use utils::*; 108 | pub(crate) use y_to_rgba::sse_y_to_rgba_row; 109 | pub(crate) use y_to_rgba_alpha::sse_y_to_rgba_alpha_row; 110 | pub(crate) use yuv_nv_p16_to_rgb::sse_yuv_nv_p16_to_rgba_row; 111 | pub(crate) use yuv_nv_to_rgba::sse_yuv_nv_to_rgba; 112 | pub(crate) use yuv_nv_to_rgba420::sse_yuv_nv_to_rgba420; 113 | #[cfg(feature = "professional_mode")] 114 | pub(crate) use yuv_nv_to_rgba420_prof::sse_yuv_nv_to_rgba_row420_prof; 115 | pub(crate) use yuv_nv_to_rgba422::sse_yuv_nv_to_rgba422; 116 | #[cfg(feature = "fast_mode")] 117 | pub(crate) use yuv_nv_to_rgba_fast::sse_yuv_nv_to_rgba_fast; 118 | #[cfg(feature = "fast_mode")] 119 | pub(crate) use yuv_nv_to_rgba_fast420::sse_yuv_nv_to_rgba_fast420; 120 | #[cfg(feature = "professional_mode")] 121 | pub(crate) use yuv_nv_to_rgba_prof::sse_yuv_nv_to_rgba_row_prof; 122 | pub(crate) use yuv_p16_to_rgb16::sse_yuv_p16_to_rgba_row; 123 | pub(crate) use yuv_p16_to_rgb16_alpha::sse_yuv_p16_to_rgba_alpha_row; 124 | pub(crate) use yuv_p16_to_rgb8::sse_yuv_p16_to_rgba8_row; 125 | pub(crate) use yuv_p16_to_rgb8_alpha::sse_yuv_p16_to_rgba8_alpha_row; 126 | pub(crate) use yuv_to_rgba::sse_yuv_to_rgba_row; 127 | pub(crate) use yuv_to_rgba420::sse_yuv_to_rgba_row420; 128 | pub(crate) use yuv_to_rgba422::sse_yuv_to_rgba_row422; 129 | pub(crate) use yuv_to_rgba_alpha::sse_yuv_to_rgba_alpha_row; 130 | pub(crate) use yuv_to_yuy2::yuv_to_yuy2_sse; 131 | pub(crate) use yuy2_to_rgb::yuy2_to_rgb_sse; 132 | pub(crate) use yuy2_to_yuv::yuy2_to_yuv_sse; 133 | -------------------------------------------------------------------------------- /src/sse/y_to_rgba.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::sse::{ 31 | _mm_expand8_hi_to_10, _mm_expand8_lo_to_10, _mm_store_interleave_half_rgb_for_yuv, 32 | _mm_store_interleave_rgb_for_yuv, 33 | }; 34 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 35 | #[cfg(target_arch = "x86")] 36 | use std::arch::x86::*; 37 | #[cfg(target_arch = "x86_64")] 38 | use std::arch::x86_64::*; 39 | 40 | pub(crate) fn sse_y_to_rgba_row( 41 | range: &YuvChromaRange, 42 | transform: &CbCrInverseTransform, 43 | y_plane: &[u8], 44 | rgba: &mut [u8], 45 | start_cx: usize, 46 | width: usize, 47 | ) { 48 | unsafe { 49 | sse_y_to_rgba_row_impl::( 50 | range, transform, y_plane, rgba, start_cx, width, 51 | ) 52 | } 53 | } 54 | 55 | #[target_feature(enable = "sse4.1")] 56 | unsafe fn sse_y_to_rgba_row_impl( 57 | range: &YuvChromaRange, 58 | transform: &CbCrInverseTransform, 59 | y_plane: &[u8], 60 | rgba: &mut [u8], 61 | start_cx: usize, 62 | width: usize, 63 | ) { 64 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 65 | let channels = destination_channels.get_channels_count(); 66 | 67 | let mut cx = start_cx; 68 | 69 | let y_ptr = y_plane.as_ptr(); 70 | let rgba_ptr = rgba.as_mut_ptr(); 71 | 72 | let y_corr = _mm_set1_epi8(range.bias_y as i8); 73 | let v_luma_coeff = _mm_set1_epi16(transform.y_coef as i16); 74 | 75 | let zeros = _mm_setzero_si128(); 76 | 77 | while cx + 16 < width { 78 | let y_values = _mm_subs_epu8(_mm_loadu_si128(y_ptr.add(cx) as *const __m128i), y_corr); 79 | 80 | let vh = _mm_expand8_hi_to_10(y_values); 81 | let vl = _mm_expand8_lo_to_10(y_values); 82 | 83 | let v_high = _mm_mulhrs_epi16(vh, v_luma_coeff); 84 | let v_low = _mm_mulhrs_epi16(vl, v_luma_coeff); 85 | 86 | let v_values = _mm_packus_epi16(v_low, v_high); 87 | 88 | let dst_shift = cx * channels; 89 | 90 | let v_alpha = _mm_set1_epi8(255u8 as i8); 91 | 92 | _mm_store_interleave_rgb_for_yuv::( 93 | rgba_ptr.add(dst_shift), 94 | v_values, 95 | v_values, 96 | v_values, 97 | v_alpha, 98 | ); 99 | 100 | cx += 16; 101 | } 102 | 103 | while cx + 8 < width { 104 | let y_values = _mm_subs_epi8(_mm_loadu_si64(y_ptr.add(cx)), y_corr); 105 | 106 | let v_low = _mm_mulhrs_epi16(_mm_expand8_lo_to_10(y_values), v_luma_coeff); 107 | 108 | let v_values = _mm_packus_epi16(v_low, zeros); 109 | 110 | let dst_shift = cx * channels; 111 | 112 | let v_alpha = _mm_set1_epi8(255u8 as i8); 113 | 114 | _mm_store_interleave_half_rgb_for_yuv::( 115 | rgba_ptr.add(dst_shift), 116 | v_values, 117 | v_values, 118 | v_values, 119 | v_alpha, 120 | ); 121 | 122 | cx += 8; 123 | } 124 | 125 | if cx < width { 126 | let diff = width - cx; 127 | assert!(diff <= 8); 128 | 129 | let mut y_buffer: [u8; 8] = [0; 8]; 130 | let mut dst_buffer: [u8; 8 * 4] = [0; 8 * 4]; 131 | std::ptr::copy_nonoverlapping( 132 | y_plane.get_unchecked(cx..).as_ptr(), 133 | y_buffer.as_mut_ptr(), 134 | diff, 135 | ); 136 | 137 | let y_values = _mm_subs_epi8(_mm_loadu_si64(y_buffer.as_ptr()), y_corr); 138 | 139 | let v_low = _mm_mulhrs_epi16(_mm_expand8_lo_to_10(y_values), v_luma_coeff); 140 | 141 | let v_values = _mm_packus_epi16(v_low, zeros); 142 | 143 | let v_alpha = _mm_set1_epi8(255u8 as i8); 144 | 145 | _mm_store_interleave_half_rgb_for_yuv::( 146 | dst_buffer.as_mut_ptr(), 147 | v_values, 148 | v_values, 149 | v_values, 150 | v_alpha, 151 | ); 152 | 153 | let dst_shift = cx * channels; 154 | 155 | std::ptr::copy_nonoverlapping( 156 | dst_buffer.as_ptr(), 157 | rgba_ptr.add(dst_shift), 158 | diff * channels, 159 | ); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/sse/y_to_rgba_alpha.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::sse::{ 31 | _mm_expand8_hi_to_10, _mm_expand8_lo_to_10, _mm_store_interleave_half_rgb_for_yuv, 32 | _mm_store_interleave_rgb_for_yuv, 33 | }; 34 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 35 | #[cfg(target_arch = "x86")] 36 | use std::arch::x86::*; 37 | #[cfg(target_arch = "x86_64")] 38 | use std::arch::x86_64::*; 39 | 40 | pub(crate) fn sse_y_to_rgba_alpha_row( 41 | range: &YuvChromaRange, 42 | transform: &CbCrInverseTransform, 43 | y_plane: &[u8], 44 | a_plane: &[u8], 45 | rgba: &mut [u8], 46 | start_cx: usize, 47 | width: usize, 48 | ) -> usize { 49 | unsafe { 50 | sse_y_to_rgba_alpha_row_impl::( 51 | range, transform, y_plane, a_plane, rgba, start_cx, width, 52 | ) 53 | } 54 | } 55 | 56 | #[target_feature(enable = "sse4.1")] 57 | unsafe fn sse_y_to_rgba_alpha_row_impl( 58 | range: &YuvChromaRange, 59 | transform: &CbCrInverseTransform, 60 | y_plane: &[u8], 61 | a_plane: &[u8], 62 | rgba: &mut [u8], 63 | start_cx: usize, 64 | width: usize, 65 | ) -> usize { 66 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 67 | let channels = destination_channels.get_channels_count(); 68 | 69 | let mut cx = start_cx; 70 | 71 | let y_ptr = y_plane.as_ptr(); 72 | let rgba_ptr = rgba.as_mut_ptr(); 73 | 74 | let y_corr = _mm_set1_epi8(range.bias_y as i8); 75 | let v_luma_coeff = _mm_set1_epi16(transform.y_coef as i16); 76 | 77 | let zeros = _mm_setzero_si128(); 78 | 79 | while cx + 16 < width { 80 | let y_vl = _mm_loadu_si128(y_ptr.add(cx) as *const __m128i); 81 | let a_values = _mm_loadu_si128(a_plane.get_unchecked(cx..).as_ptr() as *const __m128i); 82 | 83 | let y_values = _mm_subs_epu8(y_vl, y_corr); 84 | 85 | let vhl = _mm_expand8_hi_to_10(y_values); 86 | let vll = _mm_expand8_lo_to_10(y_values); 87 | 88 | let v_high = _mm_mulhrs_epi16(vhl, v_luma_coeff); 89 | let v_low = _mm_mulhrs_epi16(vll, v_luma_coeff); 90 | 91 | let v_values = _mm_packus_epi16(v_low, v_high); 92 | 93 | let dst_shift = cx * channels; 94 | 95 | _mm_store_interleave_rgb_for_yuv::( 96 | rgba_ptr.add(dst_shift), 97 | v_values, 98 | v_values, 99 | v_values, 100 | a_values, 101 | ); 102 | 103 | cx += 16; 104 | } 105 | 106 | while cx + 8 < width { 107 | let y_values = _mm_subs_epi8(_mm_loadu_si64(y_ptr.add(cx)), y_corr); 108 | let a_values = _mm_loadu_si64(a_plane.get_unchecked(cx..).as_ptr()); 109 | 110 | let v_low = _mm_mulhrs_epi16(_mm_expand8_lo_to_10(y_values), v_luma_coeff); 111 | 112 | let v_values = _mm_packus_epi16(v_low, zeros); 113 | 114 | let dst_shift = cx * channels; 115 | 116 | _mm_store_interleave_half_rgb_for_yuv::( 117 | rgba_ptr.add(dst_shift), 118 | v_values, 119 | v_values, 120 | v_values, 121 | a_values, 122 | ); 123 | 124 | cx += 8; 125 | } 126 | 127 | cx 128 | } 129 | -------------------------------------------------------------------------------- /src/wasm32/mod.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | mod transpose; 30 | mod utils; 31 | mod y_to_rgb; 32 | mod yuv_nv_to_rgba; 33 | mod yuv_nv_to_rgba420; 34 | mod yuv_to_rgba; 35 | mod yuv_to_rgba420; 36 | 37 | pub(crate) use y_to_rgb::wasm_y_to_rgb_row; 38 | pub(crate) use yuv_nv_to_rgba::wasm_yuv_nv_to_rgba_row; 39 | pub(super) use yuv_nv_to_rgba420::wasm_yuv_nv_to_rgba_row420; 40 | pub(crate) use yuv_to_rgba::wasm_yuv_to_rgba_row; 41 | pub(super) use yuv_to_rgba420::wasm_yuv_to_rgba_row420; 42 | -------------------------------------------------------------------------------- /src/wasm32/transpose.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::wasm32::utils::{wasm_unpackhi_i8x16, wasm_unpacklo_i8x16}; 30 | use std::arch::wasm32::*; 31 | 32 | #[inline] 33 | pub(crate) unsafe fn v128_deinterleave_u8_x2(a: v128, b: v128) -> (v128, v128) { 34 | let x0 = u8x16_shuffle::<0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30>(a, b); 35 | let x1 = u8x16_shuffle::<1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31>(a, b); 36 | (x0, x1) 37 | } 38 | 39 | #[inline] 40 | pub(crate) unsafe fn v128_load_deinterleave_u8_x2(ptr: *const u8) -> (v128, v128) { 41 | let a = v128_load(ptr as *const v128); 42 | let b = v128_load(ptr.add(16) as *const v128); 43 | v128_deinterleave_u8_x2(a, b) 44 | } 45 | 46 | #[inline] 47 | pub(crate) unsafe fn v128_load_deinterleave_half_u8_x2(ptr: *const u8) -> (v128, v128) { 48 | let a = v128_load(ptr as *const v128); 49 | v128_deinterleave_u8_x2(a, u8x16_splat(0)) 50 | } 51 | 52 | #[inline] 53 | pub(crate) unsafe fn wasm_store_interleave_u8x4(ptr: *mut u8, packed: (v128, v128, v128, v128)) { 54 | let a = packed.0; 55 | let b = packed.1; 56 | let c = packed.2; 57 | let d = packed.3; 58 | // a0 a1 a2 a3 .... 59 | // b0 b1 b2 b3 .... 60 | // c0 c1 c2 c3 .... 61 | // d0 d1 d2 d3 .... 62 | let u0 = wasm_unpacklo_i8x16(a, c); // a0 c0 a1 c1 ... 63 | let u1 = wasm_unpackhi_i8x16(a, c); // a8 c8 a9 c9 ... 64 | let u2 = wasm_unpacklo_i8x16(b, d); // b0 d0 b1 d1 ... 65 | let u3 = wasm_unpackhi_i8x16(b, d); // b8 d8 b9 d9 ... 66 | 67 | let v0 = wasm_unpacklo_i8x16(u0, u2); // a0 b0 c0 d0 ... 68 | let v1 = wasm_unpackhi_i8x16(u0, u2); // a4 b4 c4 d4 ... 69 | let v2 = wasm_unpacklo_i8x16(u1, u3); // a8 b8 c8 d8 ... 70 | let v3 = wasm_unpackhi_i8x16(u1, u3); // a12 b12 c12 d12 ... 71 | 72 | v128_store(ptr as *mut v128, v0); 73 | v128_store(ptr.add(16) as *mut v128, v1); 74 | v128_store(ptr.add(32) as *mut v128, v2); 75 | v128_store(ptr.add(48) as *mut v128, v3); 76 | } 77 | 78 | #[inline] 79 | pub(crate) unsafe fn wasm_store_interleave_u8x3(ptr: *mut u8, packed: (v128, v128, v128)) { 80 | let a = packed.0; 81 | let b = packed.1; 82 | let c = packed.2; 83 | let t00 = u8x16_shuffle::<0, 16, 0, 1, 17, 0, 2, 18, 0, 3, 19, 0, 4, 20, 0, 5>(a, b); 84 | let t01 = u8x16_shuffle::<21, 0, 6, 22, 0, 7, 23, 0, 8, 24, 0, 9, 25, 0, 10, 26>(a, b); 85 | let t02 = u8x16_shuffle::<0, 11, 27, 0, 12, 28, 0, 13, 29, 0, 14, 30, 0, 15, 31, 0>(a, b); 86 | 87 | let t10 = u8x16_shuffle::<0, 1, 16, 3, 4, 17, 6, 7, 18, 9, 10, 19, 12, 13, 20, 15>(t00, c); 88 | let t11 = u8x16_shuffle::<0, 21, 2, 3, 22, 5, 6, 23, 8, 9, 24, 11, 12, 25, 14, 15>(t01, c); 89 | let t12 = u8x16_shuffle::<26, 1, 2, 27, 4, 5, 28, 7, 8, 29, 10, 11, 30, 13, 14, 31>(t02, c); 90 | 91 | v128_store(ptr as *mut v128, t10); 92 | v128_store(ptr.add(16) as *mut v128, t11); 93 | v128_store(ptr.add(32) as *mut v128, t12); 94 | } 95 | -------------------------------------------------------------------------------- /src/wasm32/utils.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | use crate::wasm32::transpose::{wasm_store_interleave_u8x3, wasm_store_interleave_u8x4}; 30 | use crate::yuv_support::YuvSourceChannels; 31 | use std::arch::wasm32::*; 32 | 33 | #[inline] 34 | pub(crate) unsafe fn v128_load_half(ptr: *const u8) -> v128 { 35 | u64x2_replace_lane::<0>(i64x2_splat(0), (ptr as *const u64).read_unaligned()) 36 | } 37 | 38 | /// Packs two i16x8 into one u8x16 using unsigned saturation 39 | #[inline] 40 | pub(crate) unsafe fn i16x8_pack_sat_u8x16(a: v128, b: v128) -> v128 { 41 | let maxval = u16x8_splat(255); 42 | let minval = u16x8_splat(0); 43 | let mut a1 = v128_bitselect(maxval, a, i16x8_gt(a, maxval)); 44 | a1 = v128_bitselect(minval, a1, i16x8_lt(a, minval)); 45 | let mut b1 = v128_bitselect(maxval, b, i16x8_gt(b, maxval)); 46 | b1 = v128_bitselect(minval, b1, i16x8_lt(b, minval)); 47 | u8x16_shuffle::<0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30>(a1, b1) 48 | } 49 | 50 | #[inline] 51 | #[allow(dead_code)] 52 | pub(crate) unsafe fn wasm_zip_lo_i8x16(a: v128, b: v128) -> v128 { 53 | u8x16_shuffle::<0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23>(a, b) 54 | } 55 | 56 | #[inline] 57 | #[allow(dead_code)] 58 | pub(crate) unsafe fn wasm_unpacklo_i8x16(a: v128, b: v128) -> v128 { 59 | u8x16_shuffle::<0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23>(a, b) 60 | } 61 | 62 | #[inline] 63 | #[allow(dead_code)] 64 | pub(crate) unsafe fn wasm_unpacklo_i16x8(a: v128, b: v128) -> v128 { 65 | u8x16_shuffle::<0, 1, 16, 17, 2, 3, 18, 19, 4, 5, 20, 21, 6, 7, 22, 23>(a, b) 66 | } 67 | 68 | #[inline] 69 | #[allow(dead_code)] 70 | pub(crate) unsafe fn wasm_unpacklo_i32x4(a: v128, b: v128) -> v128 { 71 | u8x16_shuffle::<0, 1, 2, 3, 16, 17, 18, 19, 4, 5, 6, 7, 20, 21, 22, 23>(a, b) 72 | } 73 | 74 | #[inline] 75 | #[allow(dead_code)] 76 | pub(crate) unsafe fn wasm_unpacklo_i64x2(a: v128, b: v128) -> v128 { 77 | u8x16_shuffle::<0, 1, 2, 3, 4, 5, 6, 7, 16, 17, 18, 19, 20, 21, 22, 23>(a, b) 78 | } 79 | 80 | #[inline] 81 | #[allow(dead_code)] 82 | pub(crate) unsafe fn wasm_unpackhi_i8x16(a: v128, b: v128) -> v128 { 83 | u8x16_shuffle::<8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31>(a, b) 84 | } 85 | 86 | #[inline] 87 | #[allow(dead_code)] 88 | pub(crate) unsafe fn wasm_unpackhi_i16x8(a: v128, b: v128) -> v128 { 89 | u8x16_shuffle::<8, 9, 24, 25, 10, 11, 26, 27, 12, 13, 28, 29, 14, 15, 30, 31>(a, b) 90 | } 91 | 92 | #[inline] 93 | #[allow(dead_code)] 94 | pub(crate) unsafe fn wasm_unpackhi_i32x4(a: v128, b: v128) -> v128 { 95 | u8x16_shuffle::<8, 9, 10, 11, 24, 25, 26, 27, 12, 13, 14, 15, 28, 29, 30, 31>(a, b) 96 | } 97 | 98 | #[inline] 99 | #[allow(dead_code)] 100 | pub(crate) unsafe fn wasm_unpackhi_i64x2(a: v128, b: v128) -> v128 { 101 | u8x16_shuffle::<8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26, 27, 28, 29, 30, 31>(a, b) 102 | } 103 | 104 | #[inline(always)] 105 | pub(crate) unsafe fn wasm_store_rgb( 106 | ptr: *mut u8, 107 | r: v128, 108 | g: v128, 109 | b: v128, 110 | a: v128, 111 | ) { 112 | let destination_channels: YuvSourceChannels = CN.into(); 113 | match destination_channels { 114 | YuvSourceChannels::Rgb => { 115 | let dst_pack = (r, g, b); 116 | wasm_store_interleave_u8x3(ptr, dst_pack); 117 | } 118 | YuvSourceChannels::Bgr => { 119 | let dst_pack = (b, g, r); 120 | wasm_store_interleave_u8x3(ptr, dst_pack); 121 | } 122 | YuvSourceChannels::Rgba => { 123 | let dst_pack = (r, g, b, a); 124 | wasm_store_interleave_u8x4(ptr, dst_pack); 125 | } 126 | YuvSourceChannels::Bgra => { 127 | let dst_pack = (b, g, r, a); 128 | wasm_store_interleave_u8x4(ptr, dst_pack); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/wasm32/y_to_rgb.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::wasm32::utils::{i16x8_pack_sat_u8x16, wasm_store_rgb}; 31 | use crate::yuv_support::{CbCrInverseTransform, YuvChromaRange, YuvSourceChannels}; 32 | use std::arch::wasm32::*; 33 | 34 | #[target_feature(enable = "simd128")] 35 | pub(crate) unsafe fn wasm_y_to_rgb_row( 36 | range: &YuvChromaRange, 37 | transform: &CbCrInverseTransform, 38 | y_plane: &[u8], 39 | rgba: &mut [u8], 40 | start_cx: usize, 41 | width: usize, 42 | ) { 43 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 44 | let channels = destination_channels.get_channels_count(); 45 | 46 | let y_corr = u8x16_splat(range.bias_y as u8); 47 | let v_luma_coeff = i16x8_splat(transform.y_coef as i16); 48 | let v_alpha = u8x16_splat(255u8); 49 | 50 | let mut cx = start_cx; 51 | 52 | const SCALE: u32 = 2; 53 | 54 | while cx + 16 < width { 55 | let y_values = u8x16_sub_sat( 56 | v128_load(y_plane.get_unchecked(cx..).as_ptr() as *const v128), 57 | y_corr, 58 | ); 59 | 60 | let y_high = u16x8_shl(u16x8_extend_high_u8x16(y_values), SCALE); 61 | let r_high = i16x8_q15mulr_sat(y_high, v_luma_coeff); 62 | 63 | let y_low = u16x8_shl(u16x8_extend_low_u8x16(y_values), SCALE); 64 | let r_low = i16x8_q15mulr_sat(y_low, v_luma_coeff); 65 | 66 | let r_values = i16x8_pack_sat_u8x16(r_low, r_high); 67 | 68 | let dst_shift = cx * channels; 69 | 70 | wasm_store_rgb::( 71 | rgba.get_unchecked_mut(dst_shift..).as_mut_ptr(), 72 | r_values, 73 | r_values, 74 | r_values, 75 | v_alpha, 76 | ); 77 | 78 | cx += 16; 79 | } 80 | 81 | if cx < width { 82 | let diff = width - cx; 83 | assert!(diff <= 16); 84 | 85 | let mut y_buffer: [u8; 16] = [0; 16]; 86 | let mut dst_buffer: [u8; 16 * 4] = [0; 16 * 4]; 87 | std::ptr::copy_nonoverlapping( 88 | y_plane.get_unchecked(cx..).as_ptr(), 89 | y_buffer.as_mut_ptr(), 90 | diff, 91 | ); 92 | 93 | let y_values = u8x16_sub_sat(v128_load(y_buffer.as_ptr() as *const v128), y_corr); 94 | 95 | let y_high = u16x8_shl(u16x8_extend_high_u8x16(y_values), SCALE); 96 | let r_high = i16x8_q15mulr_sat(y_high, v_luma_coeff); 97 | 98 | let y_low = u16x8_shl(u16x8_extend_low_u8x16(y_values), SCALE); 99 | let r_low = i16x8_q15mulr_sat(y_low, v_luma_coeff); 100 | 101 | let r_values = i16x8_pack_sat_u8x16(r_low, r_high); 102 | 103 | wasm_store_rgb::( 104 | dst_buffer.as_mut_ptr(), 105 | r_values, 106 | r_values, 107 | r_values, 108 | v_alpha, 109 | ); 110 | 111 | let dst_shift = cx * channels; 112 | 113 | std::ptr::copy_nonoverlapping( 114 | dst_buffer.as_ptr(), 115 | rgba.get_unchecked_mut(dst_shift..).as_mut_ptr(), 116 | diff * channels, 117 | ); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/wasm32/yuv_to_rgba.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | use crate::internals::ProcessedOffset; 31 | use crate::wasm32::utils::{ 32 | i16x8_pack_sat_u8x16, v128_load_half, wasm_store_rgb, wasm_zip_lo_i8x16, 33 | }; 34 | use crate::yuv_support::{ 35 | CbCrInverseTransform, YuvChromaRange, YuvChromaSubsampling, YuvSourceChannels, 36 | }; 37 | use std::arch::wasm32::*; 38 | 39 | #[target_feature(enable = "simd128")] 40 | pub(crate) unsafe fn wasm_yuv_to_rgba_row( 41 | range: &YuvChromaRange, 42 | transform: &CbCrInverseTransform, 43 | y_plane: &[u8], 44 | u_plane: &[u8], 45 | v_plane: &[u8], 46 | rgba: &mut [u8], 47 | start_cx: usize, 48 | start_ux: usize, 49 | width: usize, 50 | ) -> ProcessedOffset { 51 | let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into(); 52 | let destination_channels: YuvSourceChannels = DESTINATION_CHANNELS.into(); 53 | let channels = destination_channels.get_channels_count(); 54 | 55 | let mut cx = start_cx; 56 | let mut uv_x = start_ux; 57 | 58 | let y_ptr = y_plane.as_ptr(); 59 | let u_ptr = u_plane.as_ptr(); 60 | let v_ptr = v_plane.as_ptr(); 61 | let rgba_ptr = rgba.as_mut_ptr(); 62 | 63 | let y_corr = u8x16_splat(range.bias_y as u8); 64 | let uv_corr = i16x8_splat(range.bias_uv as i16); 65 | let v_luma_coeff = i16x8_splat(transform.y_coef as i16); 66 | let v_cr_coeff = i16x8_splat(transform.cr_coef as i16); 67 | let v_cb_coeff = i16x8_splat(transform.cb_coef as i16); 68 | let v_g_coeff_1 = i16x8_splat(-1i16 * transform.g_coeff_1 as i16); 69 | let v_g_coeff_2 = i16x8_splat(-1i16 * transform.g_coeff_2 as i16); 70 | let v_alpha = u8x16_splat(255u8); 71 | 72 | const V_SCALE: u32 = 2; 73 | 74 | while cx + 16 < width { 75 | let y_values = u8x16_sub_sat(v128_load(y_ptr.add(cx) as *const v128), y_corr); 76 | 77 | let u_high_u16; 78 | let v_high_u16; 79 | let u_low_u16; 80 | let v_low_u16; 81 | 82 | match chroma_subsampling { 83 | YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => { 84 | let mut u_values = v128_load_half(u_ptr.add(uv_x)); 85 | let mut v_values = v128_load_half(v_ptr.add(uv_x)); 86 | 87 | u_values = wasm_zip_lo_i8x16(u_values, u_values); 88 | v_values = wasm_zip_lo_i8x16(v_values, v_values); 89 | 90 | u_high_u16 = u16x8_extend_high_u8x16(u_values); 91 | v_high_u16 = u16x8_extend_high_u8x16(v_values); 92 | u_low_u16 = u16x8_extend_low_u8x16(u_values); 93 | v_low_u16 = u16x8_extend_low_u8x16(v_values); 94 | } 95 | YuvChromaSubsampling::Yuv444 => { 96 | let u_values = v128_load(u_ptr.add(uv_x) as *const v128); 97 | let v_values = v128_load(v_ptr.add(uv_x) as *const v128); 98 | 99 | u_high_u16 = u16x8_extend_high_u8x16(u_values); 100 | v_high_u16 = u16x8_extend_high_u8x16(v_values); 101 | u_low_u16 = u16x8_extend_low_u8x16(u_values); 102 | v_low_u16 = u16x8_extend_low_u8x16(v_values); 103 | } 104 | } 105 | 106 | let u_high = i16x8_shl(i16x8_sub(u_high_u16, uv_corr), V_SCALE); 107 | let v_high = i16x8_shl(i16x8_sub(v_high_u16, uv_corr), V_SCALE); 108 | let y_high = i16x8_q15mulr_sat( 109 | i16x8_shl(u16x8_extend_high_u8x16(y_values), V_SCALE), 110 | v_luma_coeff, 111 | ); 112 | 113 | let r_high = i16x8_add(y_high, i16x8_q15mulr_sat(v_high, v_cr_coeff)); 114 | let b_high = i16x8_add(y_high, i16x8_q15mulr_sat(u_high, v_cb_coeff)); 115 | let g_high = i16x8_add( 116 | y_high, 117 | i16x8_add( 118 | i16x8_q15mulr_sat(v_high, v_g_coeff_1), 119 | i16x8_q15mulr_sat(u_high, v_g_coeff_2), 120 | ), 121 | ); 122 | 123 | let u_low = i16x8_shl(i16x8_sub(u_low_u16, uv_corr), V_SCALE); 124 | let v_low = i16x8_shl(i16x8_sub(v_low_u16, uv_corr), V_SCALE); 125 | let y_low = i16x8_q15mulr_sat( 126 | i16x8_shl(u16x8_extend_low_u8x16(y_values), V_SCALE), 127 | v_luma_coeff, 128 | ); 129 | 130 | let r_low = i16x8_add(y_low, i16x8_q15mulr_sat(v_low, v_cr_coeff)); 131 | let b_low = i16x8_add(y_low, i16x8_q15mulr_sat(u_low, v_cb_coeff)); 132 | let g_low = i16x8_add( 133 | y_low, 134 | i16x8_add( 135 | i16x8_q15mulr_sat(v_low, v_g_coeff_1), 136 | i16x8_q15mulr_sat(u_low, v_g_coeff_2), 137 | ), 138 | ); 139 | 140 | let r_values = i16x8_pack_sat_u8x16(r_low, r_high); 141 | let g_values = i16x8_pack_sat_u8x16(g_low, g_high); 142 | let b_values = i16x8_pack_sat_u8x16(b_low, b_high); 143 | 144 | let dst_shift = cx * channels; 145 | 146 | wasm_store_rgb::( 147 | rgba_ptr.add(dst_shift), 148 | r_values, 149 | g_values, 150 | b_values, 151 | v_alpha, 152 | ); 153 | 154 | cx += 16; 155 | 156 | match chroma_subsampling { 157 | YuvChromaSubsampling::Yuv420 | YuvChromaSubsampling::Yuv422 => { 158 | uv_x += 8; 159 | } 160 | YuvChromaSubsampling::Yuv444 => { 161 | uv_x += 16; 162 | } 163 | } 164 | } 165 | 166 | ProcessedOffset { cx, ux: uv_x } 167 | } 168 | -------------------------------------------------------------------------------- /src/ycgcor_support.rs: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) Radzivon Bartoshyk, 10/2024. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without modification, 5 | * are permitted provided that the following conditions are met: 6 | * 7 | * 1. Redistributions of source code must retain the above copyright notice, this 8 | * list of conditions and the following disclaimer. 9 | * 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * 3. Neither the name of the copyright holder nor the names of its 15 | * contributors may be used to endorse or promote products derived from 16 | * this software without specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | */ 29 | 30 | #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] 31 | pub enum YCgCoR { 32 | YCgCoRo = 1, 33 | YCgCoRe = 2, 34 | } 35 | 36 | impl From for YCgCoR { 37 | fn from(value: usize) -> Self { 38 | match value { 39 | 1 => YCgCoR::YCgCoRo, 40 | 2 => YCgCoR::YCgCoRe, 41 | _ => { 42 | panic!("Not found suitable type of YCgCoR for {value}"); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /wasm/.gitignore: -------------------------------------------------------------------------------- 1 | www 2 | -------------------------------------------------------------------------------- /wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wasm" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | wasm-bindgen = "0.2.93" 8 | yuvutils-rs = {path = "../"} 9 | image = {version = "0.25.2", features = ["default"]} 10 | js-sys = "0.3.70" 11 | wee_alloc = "0.4.5" 12 | console_error_panic_hook = "0.1.7" 13 | 14 | 15 | [lib] 16 | crate-type = ["cdylib"] 17 | -------------------------------------------------------------------------------- /wasm/run.sh: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) Radzivon Bartoshyk. All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without modification, 5 | # are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 10 | # 2. Redistributions in binary form must reproduce the above copyright notice, 11 | # this list of conditions and the following disclaimer in the documentation 12 | # and/or other materials provided with the distribution. 13 | # 14 | # 3. Neither the name of the copyright holder nor the names of its 15 | # contributors may be used to endorse or promote products derived from 16 | # this software without specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | # 29 | 30 | set -e 31 | RUSTFLAGS="-C target-feature=+simd128" cargo build --target wasm32-unknown-unknown --package wasm 32 | wasm-pack build 33 | cd www 34 | rm -rf node_modules 35 | yarn install 36 | yarn start -------------------------------------------------------------------------------- /wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | extern crate wee_alloc; 2 | use image::{DynamicImage, EncodableLayout, ImageBuffer, ImageReader}; 3 | use js_sys::Uint8Array; 4 | use std::io::Cursor; 5 | use std::panic; 6 | use wasm_bindgen::prelude::wasm_bindgen; 7 | use yuv::{rgb_to_yuv_nv12, yuv_nv12_to_rgb, YuvBiPlanarImageMut, YuvChromaSubsampling, YuvRange, YuvStandardMatrix}; 8 | 9 | #[wasm_bindgen] 10 | extern "C" { 11 | fn alert(s: &str); 12 | } 13 | 14 | // Use `wee_alloc` as the global allocator. 15 | #[global_allocator] 16 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 17 | 18 | pub fn set_panic_hook() { 19 | panic::set_hook(Box::new(console_error_panic_hook::hook)); 20 | } 21 | 22 | #[wasm_bindgen] 23 | pub fn process(image: Uint8Array) -> Uint8Array { 24 | panic::set_hook(Box::new(console_error_panic_hook::hook)); 25 | let arr = image.to_vec(); 26 | let cursor = Cursor::new(arr); 27 | let img = ImageReader::new(cursor) 28 | .with_guessed_format() 29 | .unwrap() 30 | .decode() 31 | .unwrap(); 32 | let transient = img.to_rgb8(); 33 | let mut bytes = Vec::from(transient.as_bytes()); 34 | 35 | let mut planar_image = 36 | YuvBiPlanarImageMut::alloc(img.width(), img.height(), YuvChromaSubsampling::Yuv420); 37 | rgb_to_yuv_nv12( 38 | &mut planar_image, 39 | &transient, 40 | img.width() * 3, 41 | YuvRange::Limited, 42 | YuvStandardMatrix::Bt709, 43 | ) 44 | .unwrap(); 45 | bytes.fill(0); 46 | let fixed_gray = planar_image.to_fixed(); 47 | yuv_nv12_to_rgb( 48 | &fixed_gray, 49 | &mut bytes, 50 | img.width() * 3, 51 | YuvRange::Limited, 52 | YuvStandardMatrix::Bt709, 53 | ) 54 | .unwrap(); 55 | 56 | let img = ImageBuffer::from_raw(img.width(), img.height(), bytes) 57 | .map(DynamicImage::ImageRgb8) 58 | .expect("Failed to create image from raw data"); 59 | 60 | let mut bytes: Vec = Vec::new(); 61 | 62 | img.write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Jpeg) 63 | .expect("Successfully write"); 64 | 65 | let fixed_slice: &[u8] = &bytes; 66 | Uint8Array::from(fixed_slice) 67 | } 68 | --------------------------------------------------------------------------------