From 9ff475ad9b65628c1c63fc51bb48a28deb3ef5a4 Mon Sep 17 00:00:00 2001 From: Radzivon Bartoshyk Date: Thu, 21 Nov 2024 16:04:00 +0000 Subject: [PATCH 1/4] Ra30 Fixes --- app/src/main.rs | 14 +++++++------- src/neon/yuv_to_rgba.rs | 14 ++++++-------- src/neon/yuv_to_rgba_alpha.rs | 2 +- src/rgb_ar30.rs | 8 ++++---- src/rgba_to_nv.rs | 2 +- src/yuv_nv_to_rgba.rs | 31 +++++++++++++++++-------------- 6 files changed, 36 insertions(+), 35 deletions(-) diff --git a/app/src/main.rs b/app/src/main.rs index 71c269a..4808794 100644 --- a/app/src/main.rs +++ b/app/src/main.rs @@ -32,11 +32,11 @@ use std::fs::File; use std::io::Read; use std::time::Instant; use yuvutils_rs::{ - ab30_to_rgb8, ar30_to_rgb8, ra30_to_rgb8, rgb8_to_ar30, rgb_to_sharp_yuv422, rgb_to_yuv420_p16, - rgb_to_yuv422_p16, rgb_to_yuv_nv12_p16, yuv422_p16_to_ab30, yuv422_p16_to_ar30, - yuv422_p16_to_ra30, yuv422_to_rgb, yuv444_p16_to_ar30, yuv_nv12_to_rgb_p16, Rgb30ByteOrder, - SharpYuvGammaTransfer, YuvBiPlanarImageMut, YuvBytesPacking, YuvChromaSubsampling, - YuvEndianness, YuvPlanarImageMut, YuvRange, YuvStandardMatrix, + ab30_to_rgb8, ar30_to_rgb8, ra30_to_rgb8, rgb8_to_ar30, rgb8_to_ra30, rgb_to_sharp_yuv422, + rgb_to_yuv420_p16, rgb_to_yuv422_p16, rgb_to_yuv_nv12_p16, yuv422_p16_to_ab30, + yuv422_p16_to_ar30, yuv422_p16_to_ra30, yuv422_to_rgb, yuv444_p16_to_ar30, yuv_nv12_to_rgb_p16, + Rgb30ByteOrder, SharpYuvGammaTransfer, YuvBiPlanarImageMut, YuvBytesPacking, + YuvChromaSubsampling, YuvEndianness, YuvPlanarImageMut, YuvRange, YuvStandardMatrix, }; fn read_file_bytes(file_path: &str) -> Result, String> { @@ -222,7 +222,7 @@ fn main() { let mut ar30 = vec![0u32; width as usize * height as usize]; - rgb8_to_ar30( + rgb8_to_ra30( &mut ar30, width, Rgb30ByteOrder::Host, @@ -246,7 +246,7 @@ fn main() { // ) // .unwrap(); rgba.fill(0); - ar30_to_rgb8( + ra30_to_rgb8( &ar30, width, Rgb30ByteOrder::Host, diff --git a/src/neon/yuv_to_rgba.rs b/src/neon/yuv_to_rgba.rs index 1ac51f5..61fecf7 100644 --- a/src/neon/yuv_to_rgba.rs +++ b/src/neon/yuv_to_rgba.rs @@ -72,7 +72,7 @@ pub(crate) unsafe fn neon_yuv_to_rgba_row { let u_values = vld1_u8(u_ptr.add(uv_x)); - let v_values = vld1_u8(v_ptr.add( uv_x)); + let v_values = vld1_u8(v_ptr.add(uv_x)); u_high_u8 = vzip2_u8(u_values, u_values); v_high_u8 = vzip2_u8(v_values, v_values); @@ -81,7 +81,7 @@ pub(crate) unsafe fn neon_yuv_to_rgba_row { let u_values = vld1q_u8(u_ptr.add(uv_x)); - let v_values = vld1q_u8(v_ptr.add( uv_x)); + let v_values = vld1q_u8(v_ptr.add(uv_x)); u_high_u8 = vget_high_u8(u_values); v_high_u8 = vget_high_u8(v_values); @@ -197,17 +197,15 @@ pub(crate) unsafe fn neon_yuv_to_rgba_row { - let u_values = - vreinterpret_u8_u32(vld1_dup_u32(u_ptr.add(uv_x) as *const u32)); - let v_values = - vreinterpret_u8_u32(vld1_dup_u32(v_ptr.add( uv_x) as *const u32)); + let u_values = vreinterpret_u8_u32(vld1_dup_u32(u_ptr.add(uv_x) as *const u32)); + let v_values = vreinterpret_u8_u32(vld1_dup_u32(v_ptr.add(uv_x) as *const u32)); u_low_u8 = vzip1_u8(u_values, u_values); v_low_u8 = vzip1_u8(v_values, v_values); } YuvChromaSubsampling::Yuv444 => { let u_values = vld1_u8(u_ptr.add(uv_x)); - let v_values = vld1_u8(v_ptr.add( uv_x)); + let v_values = vld1_u8(v_ptr.add(uv_x)); u_low_u8 = u_values; v_low_u8 = v_values; @@ -286,4 +284,4 @@ pub(crate) unsafe fn neon_yuv_to_rgba_row Result<(), YuvError> { match byte_order { Rgb30ByteOrder::Host => rgb_to_ar30_impl::< - { Rgb30::Ar30 as usize }, + { Rgb30::Ra30 as usize }, { Rgb30ByteOrder::Host as usize }, { YuvSourceChannels::Rgb as u8 }, >(ar30, ar30_stride, rgb, rgb_stride, width, height), Rgb30ByteOrder::Network => rgb_to_ar30_impl::< - { Rgb30::Ar30 as usize }, + { Rgb30::Ra30 as usize }, { Rgb30ByteOrder::Network as usize }, { YuvSourceChannels::Rgb as u8 }, >(ar30, ar30_stride, rgb, rgb_stride, width, height), @@ -208,12 +208,12 @@ pub fn rgba8_to_ra30( ) -> Result<(), YuvError> { match byte_order { Rgb30ByteOrder::Host => rgb_to_ar30_impl::< - { Rgb30::Ar30 as usize }, + { Rgb30::Ra30 as usize }, { Rgb30ByteOrder::Host as usize }, { YuvSourceChannels::Rgba as u8 }, >(ar30, ar30_stride, rgba, rgba_stride, width, height), Rgb30ByteOrder::Network => rgb_to_ar30_impl::< - { Rgb30::Ar30 as usize }, + { Rgb30::Ra30 as usize }, { Rgb30ByteOrder::Network as usize }, { YuvSourceChannels::Rgba as u8 }, >(ar30, ar30_stride, rgba, rgba_stride, width, height), diff --git a/src/rgba_to_nv.rs b/src/rgba_to_nv.rs index 4b15c2f..4f688ba 100644 --- a/src/rgba_to_nv.rs +++ b/src/rgba_to_nv.rs @@ -89,7 +89,7 @@ fn rgbx_to_nv let _use_avx2 = std::arch::is_x86_feature_detected!("avx2"); #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] let is_rdm_available = std::arch::is_aarch64_feature_detected!("rdm"); - + let width = bi_planar_image.width; #[allow(unused_variables)] diff --git a/src/yuv_nv_to_rgba.rs b/src/yuv_nv_to_rgba.rs index ca9c71c..b2cd317 100644 --- a/src/yuv_nv_to_rgba.rs +++ b/src/yuv_nv_to_rgba.rs @@ -154,20 +154,23 @@ fn yuv_nv12_to_rgbx< { unsafe { if is_rdm_available { - let processed = - neon_yuv_nv_to_rgba_row::( - &range, - &inverse_transform, - _y_plane, - _uv_plane, - _bgra, - _offset.cx, - _offset.ux, - 0, - 0, - 0, - width as usize, - ); + let processed = neon_yuv_nv_to_rgba_row::< + UV_ORDER, + DESTINATION_CHANNELS, + YUV_CHROMA_SAMPLING, + >( + &range, + &inverse_transform, + _y_plane, + _uv_plane, + _bgra, + _offset.cx, + _offset.ux, + 0, + 0, + 0, + width as usize, + ); _offset = processed; } } From 594f1541a4e3b7dfb6b1c1005084ab70a1766de8 Mon Sep 17 00:00:00 2001 From: Radzivon Bartoshyk Date: Thu, 21 Nov 2024 16:04:08 +0000 Subject: [PATCH 2/4] Ra30 Fixes --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3a9f163..4d97a73 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ workspace = { members = ["app"] } [package] name = "yuvutils-rs" -version = "0.5.4" +version = "0.5.5" edition = "2021" description = "High performance utilities for YUV format handling and conversion." readme = "README.md" From 96a224db97e8bed0b0c28a85effcf4089aeb91d9 Mon Sep 17 00:00:00 2001 From: Radzivon Bartoshyk Date: Thu, 21 Nov 2024 18:25:26 +0000 Subject: [PATCH 3/4] Doc fix --- Cargo.lock | 2 +- src/images.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12f5c1c..c8b5e18 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1353,7 +1353,7 @@ dependencies = [ [[package]] name = "yuvutils-rs" -version = "0.5.4" +version = "0.5.5" dependencies = [ "num-traits", "rayon", diff --git a/src/images.rs b/src/images.rs index 6b6c721..24aa194 100644 --- a/src/images.rs +++ b/src/images.rs @@ -58,7 +58,7 @@ impl BufferStoreMut<'_, T> { } #[derive(Debug, Clone)] -/// Non representation of Bi-Planar YUV image +/// Non-mutable representation of Bi-Planar YUV image pub struct YuvBiPlanarImage<'a, T> where T: Copy + Debug, From 6714e8c76fc0d93b8c277b41dfc128b7fd99e262 Mon Sep 17 00:00:00 2001 From: Radzivon Bartoshyk Date: Thu, 21 Nov 2024 18:35:17 +0000 Subject: [PATCH 4/4] YUV 4:0:0 full/limited range improvements --- src/y_p16_to_rgb16.rs | 94 +++++++++++++--------- src/y_p16_with_alpha_to_rgb16.rs | 63 ++++++++++----- src/y_to_rgb.rs | 134 ++++++++++++++++++------------- src/y_with_alpha_to_rgb.rs | 58 ++++++++----- 4 files changed, 215 insertions(+), 134 deletions(-) diff --git a/src/y_p16_to_rgb16.rs b/src/y_p16_to_rgb16.rs index fa954b0..906dd77 100644 --- a/src/y_p16_to_rgb16.rs +++ b/src/y_p16_to_rgb16.rs @@ -53,12 +53,12 @@ fn yuv400_p16_to_rgbx< let max_colors = (1 << bit_depth) - 1; let channels = destination_channels.get_channels_count(); - let range = get_yuv_range(bit_depth, range); + let chroma_range = get_yuv_range(bit_depth, range); let kr_kb = matrix.get_kr_kb(); let transform = get_inverse_transform( max_colors, - range.range_y, - range.range_uv, + chroma_range.range_y, + chroma_range.range_uv, kr_kb.kr, kr_kb.kb, ); @@ -68,7 +68,7 @@ fn yuv400_p16_to_rgbx< let inverse_transform = transform.to_integers(PRECISION as u32); let y_coef = inverse_transform.y_coef; - let bias_y = range.bias_y as i32; + let bias_y = chroma_range.bias_y as i32; let iter; #[cfg(feature = "rayon")] @@ -88,45 +88,63 @@ fn yuv400_p16_to_rgbx< ); } - iter.for_each(|(rgba16, y_plane)| { - let mut _cx = 0usize; + match range { + YuvRange::Limited => { + iter.for_each(|(rgba16, y_plane)| { + let mut _cx = 0usize; - #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] - { - unsafe { - let offset = neon_y_p16_to_rgba16_row::< - DESTINATION_CHANNELS, - ENDIANNESS, - BYTES_POSITION, - PRECISION, - >( - y_plane.as_ptr(), - rgba16.as_mut_ptr(), - gray_image.width, - &range, - &inverse_transform, - 0, - bit_depth as usize, - ); - _cx = offset.cx; - } - } + #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] + { + unsafe { + let offset = neon_y_p16_to_rgba16_row::< + DESTINATION_CHANNELS, + ENDIANNESS, + BYTES_POSITION, + PRECISION, + >( + y_plane.as_ptr(), + rgba16.as_mut_ptr(), + gray_image.width, + &chroma_range, + &inverse_transform, + 0, + bit_depth as usize, + ); + _cx = offset.cx; + } + } - for (dst, &y_src) in rgba16.chunks_exact_mut(channels).zip(y_plane).skip(_cx) { - let y_value = (y_src as i32 - bias_y) * y_coef; + for (dst, &y_src) in rgba16.chunks_exact_mut(channels).zip(y_plane).skip(_cx) { + let y_value = (y_src as i32 - bias_y) * y_coef; - let r = ((y_value + ROUNDING_CONST) >> PRECISION) - .min(max_colors as i32) - .max(0); + let r = ((y_value + ROUNDING_CONST) >> PRECISION) + .min(max_colors as i32) + .max(0); - dst[destination_channels.get_r_channel_offset()] = r as u16; - dst[destination_channels.get_g_channel_offset()] = r as u16; - dst[destination_channels.get_b_channel_offset()] = r as u16; - if destination_channels.has_alpha() { - dst[destination_channels.get_a_channel_offset()] = max_colors as u16; - } + dst[destination_channels.get_r_channel_offset()] = r as u16; + dst[destination_channels.get_g_channel_offset()] = r as u16; + dst[destination_channels.get_b_channel_offset()] = r as u16; + if destination_channels.has_alpha() { + dst[destination_channels.get_a_channel_offset()] = max_colors as u16; + } + } + }); } - }); + YuvRange::Full => { + iter.for_each(|(rgba16, y_plane)| { + for (dst, &y_src) in rgba16.chunks_exact_mut(channels).zip(y_plane) { + let r = y_src; + + dst[destination_channels.get_r_channel_offset()] = r; + dst[destination_channels.get_g_channel_offset()] = r; + dst[destination_channels.get_b_channel_offset()] = r; + if destination_channels.has_alpha() { + dst[destination_channels.get_a_channel_offset()] = max_colors as u16; + } + } + }); + } + } Ok(()) } diff --git a/src/y_p16_with_alpha_to_rgb16.rs b/src/y_p16_with_alpha_to_rgb16.rs index 18b871f..c3bc655 100644 --- a/src/y_p16_with_alpha_to_rgb16.rs +++ b/src/y_p16_with_alpha_to_rgb16.rs @@ -62,12 +62,12 @@ fn yuv400_p16_with_alpha_to_rgbx< "YUV400 with alpha cannot be called on target image without alpha" ); - let range = get_yuv_range(bit_depth, range); + let chroma_range = get_yuv_range(bit_depth, range); let kr_kb = matrix.get_kr_kb(); let transform = get_inverse_transform( max_colors, - range.range_y, - range.range_uv, + chroma_range.range_y, + chroma_range.range_uv, kr_kb.kr, kr_kb.kb, ); @@ -77,7 +77,7 @@ fn yuv400_p16_with_alpha_to_rgbx< let inverse_transform = transform.to_integers(PRECISION as u32); let y_coef = inverse_transform.y_coef; - let bias_y = range.bias_y as i32; + let bias_y = chroma_range.bias_y as i32; let iter; let y_iter; @@ -103,23 +103,44 @@ fn yuv400_p16_with_alpha_to_rgbx< .chunks_exact(gray_alpha_image.a_stride as usize); } - iter.zip(y_iter) - .zip(a_iter) - .for_each(|((rgba16, y_plane16), a_plane16)| { - for ((&y_src, &a_src), rgba) in y_plane16 - .iter() - .zip(a_plane16) - .zip(rgba16.chunks_exact_mut(channels)) - { - let r = (((y_src as i32 - bias_y) * y_coef + ROUNDING_CONST) >> PRECISION) - .min(max_colors as i32) - .max(0); - rgba[destination_channels.get_r_channel_offset()] = r as u16; - rgba[destination_channels.get_g_channel_offset()] = r as u16; - rgba[destination_channels.get_b_channel_offset()] = r as u16; - rgba[destination_channels.get_a_channel_offset()] = a_src; - } - }); + match range { + YuvRange::Limited => { + iter.zip(y_iter) + .zip(a_iter) + .for_each(|((rgba16, y_plane16), a_plane16)| { + for ((&y_src, &a_src), rgba) in y_plane16 + .iter() + .zip(a_plane16) + .zip(rgba16.chunks_exact_mut(channels)) + { + let r = (((y_src as i32 - bias_y) * y_coef + ROUNDING_CONST) >> PRECISION) + .min(max_colors as i32) + .max(0); + rgba[destination_channels.get_r_channel_offset()] = r as u16; + rgba[destination_channels.get_g_channel_offset()] = r as u16; + rgba[destination_channels.get_b_channel_offset()] = r as u16; + rgba[destination_channels.get_a_channel_offset()] = a_src; + } + }); + } + YuvRange::Full => { + iter.zip(y_iter) + .zip(a_iter) + .for_each(|((rgba16, y_plane16), a_plane16)| { + for ((&y_src, &a_src), rgba) in y_plane16 + .iter() + .zip(a_plane16) + .zip(rgba16.chunks_exact_mut(channels)) + { + let r = y_src; + rgba[destination_channels.get_r_channel_offset()] = r; + rgba[destination_channels.get_g_channel_offset()] = r; + rgba[destination_channels.get_b_channel_offset()] = r; + rgba[destination_channels.get_a_channel_offset()] = a_src; + } + }); + } + } Ok(()) } diff --git a/src/y_to_rgb.rs b/src/y_to_rgb.rs index 3537f0f..d3a9d06 100644 --- a/src/y_to_rgb.rs +++ b/src/y_to_rgb.rs @@ -67,9 +67,15 @@ fn y_to_rgbx( )?; gray_image.check_constraints()?; - let range = get_yuv_range(8, range); + let chroma_range = get_yuv_range(8, range); let kr_kb = matrix.get_kr_kb(); - let transform = get_inverse_transform(255, range.range_y, range.range_uv, kr_kb.kr, kr_kb.kb); + let transform = get_inverse_transform( + 255, + chroma_range.range_y, + chroma_range.range_uv, + kr_kb.kr, + kr_kb.kb, + ); #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] const PRECISION: i32 = 6; @@ -81,7 +87,7 @@ fn y_to_rgbx( #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] let is_rdm_available = std::arch::is_aarch64_feature_detected!("rdm"); - let bias_y = range.bias_y as i32; + let bias_y = chroma_range.bias_y as i32; #[cfg(all( any(target_arch = "x86", target_arch = "x86_64"), @@ -105,34 +111,51 @@ fn y_to_rgbx( y_iter = y_plane.chunks_exact(y_stride as usize); } - iter.zip(y_iter).for_each(|(rgba, y_plane)| { - let mut _cx = 0usize; + if range == YuvRange::Limited { + iter.zip(y_iter).for_each(|(rgba, y_plane)| { + let mut _cx = 0usize; - #[cfg(all( - any(target_arch = "x86", target_arch = "x86_64"), - feature = "nightly_avx512" - ))] - unsafe { - if _use_avx512 { - let processed = avx512_y_to_rgb_row::( - &range, - &inverse_transform, - y_plane, - rgba, - _cx, - 0, - 0, - gray_image.width as usize, - ); - _cx = processed; + #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + feature = "nightly_avx512" + ))] + unsafe { + if _use_avx512 { + let processed = avx512_y_to_rgb_row::( + &chroma_range, + &inverse_transform, + y_plane, + rgba, + _cx, + 0, + 0, + gray_image.width as usize, + ); + _cx = processed; + } + } + + #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] + unsafe { + if is_rdm_available { + let offset = neon_y_to_rgb_row::( + &chroma_range, + &inverse_transform, + y_plane, + rgba, + _cx, + 0, + 0, + gray_image.width as usize, + ); + _cx = offset; + } } - } - #[cfg(all(target_arch = "aarch64", target_feature = "neon"))] - unsafe { - if is_rdm_available { - let offset = neon_y_to_rgb_row::( - &range, + #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] + unsafe { + let offset = wasm_y_to_rgb_row::( + &chroma_range, &inverse_transform, y_plane, rgba, @@ -143,38 +166,39 @@ fn y_to_rgbx( ); _cx = offset; } - } - #[cfg(all(target_arch = "wasm32", target_feature = "simd128"))] - unsafe { - let offset = wasm_y_to_rgb_row::( - &range, - &inverse_transform, - y_plane, - rgba, - _cx, - 0, - 0, - gray_image.width as usize, - ); - _cx = offset; - } + let rgba_sliced = &mut rgba[(_cx * channels)..]; + let y_sliced = &y_plane[_cx..]; - let rgba_sliced = &mut rgba[(_cx * channels)..]; - let y_sliced = &y_plane[_cx..]; + for (y_src, rgba) in y_sliced.iter().zip(rgba_sliced.chunks_exact_mut(channels)) { + let y_value = (*y_src as i32 - bias_y) * y_coef; - for (y_src, rgba) in y_sliced.iter().zip(rgba_sliced.chunks_exact_mut(channels)) { - let y_value = (*y_src as i32 - bias_y) * y_coef; + let r = qrshr::(y_value); + rgba[destination_channels.get_r_channel_offset()] = r as u8; + rgba[destination_channels.get_g_channel_offset()] = r as u8; + rgba[destination_channels.get_b_channel_offset()] = r as u8; + if destination_channels.has_alpha() { + rgba[destination_channels.get_a_channel_offset()] = 255; + } + } + }); + } else { + iter.zip(y_iter).for_each(|(rgba, y_plane)| { + let mut _cx = 0usize; + let rgba_sliced = &mut rgba[(_cx * channels)..]; + let y_sliced = &y_plane[_cx..]; - let r = qrshr::(y_value); - rgba[destination_channels.get_r_channel_offset()] = r as u8; - rgba[destination_channels.get_g_channel_offset()] = r as u8; - rgba[destination_channels.get_b_channel_offset()] = r as u8; - if destination_channels.has_alpha() { - rgba[destination_channels.get_a_channel_offset()] = 255; + for (y_src, rgba) in y_sliced.iter().zip(rgba_sliced.chunks_exact_mut(channels)) { + let r = *y_src; + rgba[destination_channels.get_r_channel_offset()] = r; + rgba[destination_channels.get_g_channel_offset()] = r; + rgba[destination_channels.get_b_channel_offset()] = r; + if destination_channels.has_alpha() { + rgba[destination_channels.get_a_channel_offset()] = 255; + } } - } - }); + }); + } Ok(()) } diff --git a/src/y_with_alpha_to_rgb.rs b/src/y_with_alpha_to_rgb.rs index e91ed95..fb5b26f 100644 --- a/src/y_with_alpha_to_rgb.rs +++ b/src/y_with_alpha_to_rgb.rs @@ -79,12 +79,12 @@ where let max_colors = (1 << BIT_DEPTH) - 1; - let range = get_yuv_range(BIT_DEPTH as u32, range); + let chroma_range = get_yuv_range(BIT_DEPTH as u32, range); let kr_kb = matrix.get_kr_kb(); let transform = get_inverse_transform( max_colors, - range.range_y, - range.range_uv, + chroma_range.range_y, + chroma_range.range_uv, kr_kb.kr, kr_kb.kb, ); @@ -93,7 +93,7 @@ where let inverse_transform = transform.to_integers(PRECISION as u32); let y_coef = inverse_transform.y_coef; - let bias_y = range.bias_y as i32; + let bias_y = chroma_range.bias_y as i32; let iter; let y_iter; @@ -119,23 +119,41 @@ where .chunks_exact(gray_alpha_image.a_stride as usize); } - iter.zip(y_iter) - .zip(a_iter) - .for_each(|((rgba, y_plane), a_plane)| { - for ((y_src, a_src), rgba) in y_plane - .iter() - .zip(a_plane) - .zip(rgba.chunks_exact_mut(channels)) - { - let y_value = (y_src.as_() - bias_y) * y_coef; + if range == YuvRange::Limited { + iter.zip(y_iter) + .zip(a_iter) + .for_each(|((rgba, y_plane), a_plane)| { + for ((y_src, a_src), rgba) in y_plane + .iter() + .zip(a_plane) + .zip(rgba.chunks_exact_mut(channels)) + { + let y_value = (y_src.as_() - bias_y) * y_coef; - let r = qrshr::(y_value); - rgba[destination_channels.get_r_channel_offset()] = r.as_(); - rgba[destination_channels.get_g_channel_offset()] = r.as_(); - rgba[destination_channels.get_b_channel_offset()] = r.as_(); - rgba[destination_channels.get_a_channel_offset()] = *a_src; - } - }); + let r = qrshr::(y_value); + rgba[destination_channels.get_r_channel_offset()] = r.as_(); + rgba[destination_channels.get_g_channel_offset()] = r.as_(); + rgba[destination_channels.get_b_channel_offset()] = r.as_(); + rgba[destination_channels.get_a_channel_offset()] = *a_src; + } + }); + } else { + iter.zip(y_iter) + .zip(a_iter) + .for_each(|((rgba, y_plane), a_plane)| { + for ((y_src, a_src), rgba) in y_plane + .iter() + .zip(a_plane) + .zip(rgba.chunks_exact_mut(channels)) + { + let y_value = *y_src; + rgba[destination_channels.get_r_channel_offset()] = y_value; + rgba[destination_channels.get_g_channel_offset()] = y_value; + rgba[destination_channels.get_b_channel_offset()] = y_value; + rgba[destination_channels.get_a_channel_offset()] = *a_src; + } + }); + } Ok(()) }