yuvutils_rs/
yuv_p10_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#[cfg(all(
30    any(target_arch = "x86", target_arch = "x86_64"),
31    feature = "nightly_avx512"
32))]
33use crate::avx512bw::avx512_yuv_p16_to_rgba8_row;
34use crate::built_coefficients::get_built_inverse_transform;
35#[allow(dead_code, unused_imports)]
36use crate::internals::ProcessedOffset;
37#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
38use crate::neon::neon_yuv_p16_to_rgba_row;
39use crate::numerics::to_ne;
40use crate::yuv_error::check_rgba_destination;
41use crate::yuv_support::{
42    get_inverse_transform, get_yuv_range, YuvBytesPacking, YuvChromaSubsampling, YuvEndianness,
43    YuvRange, YuvSourceChannels, YuvStandardMatrix,
44};
45use crate::{YuvError, YuvPlanarImage};
46#[cfg(feature = "rayon")]
47use rayon::iter::{IndexedParallelIterator, ParallelIterator};
48#[cfg(feature = "rayon")]
49use rayon::prelude::{ParallelSlice, ParallelSliceMut};
50
51fn yuv_p16_to_image_ant<
52    const DESTINATION_CHANNELS: u8,
53    const SAMPLING: u8,
54    const ENDIANNESS: u8,
55    const BYTES_POSITION: u8,
56    const BIT_DEPTH: usize,
57>(
58    image: &YuvPlanarImage<u16>,
59    rgba: &mut [u8],
60    rgba_stride: u32,
61    range: YuvRange,
62    matrix: YuvStandardMatrix,
63) -> Result<(), YuvError> {
64    let dst_chans: YuvSourceChannels = DESTINATION_CHANNELS.into();
65    let channels = dst_chans.get_channels_count();
66
67    let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into();
68
69    assert!(
70        BIT_DEPTH == 10 || BIT_DEPTH == 12,
71        "YUV16 -> RGB8 implemented only 10 and 12 bit depth"
72    );
73
74    image.check_constraints(chroma_subsampling)?;
75    check_rgba_destination(rgba, rgba_stride, image.width, image.height, channels)?;
76
77    let chroma_range = get_yuv_range(BIT_DEPTH as u32, range);
78    let kr_kb = matrix.get_kr_kb();
79    const PRECISION: i32 = 13;
80    let i_transform = if let Some(stored) =
81        get_built_inverse_transform(PRECISION as u32, BIT_DEPTH as u32, range, matrix)
82    {
83        stored
84    } else {
85        let transform = get_inverse_transform(
86            BIT_DEPTH as u32,
87            chroma_range.range_y,
88            chroma_range.range_uv,
89            kr_kb.kr,
90            kr_kb.kb,
91        );
92        transform.to_integers(PRECISION as u32)
93    };
94    let cr_coef = i_transform.cr_coef;
95    let cb_coef = i_transform.cb_coef;
96    let y_coef = i_transform.y_coef;
97    let g_coef_1 = i_transform.g_coeff_1;
98    let g_coef_2 = i_transform.g_coeff_2;
99
100    let bias_y = chroma_range.bias_y as i32;
101    let bias_uv = chroma_range.bias_uv as i32;
102
103    let msb_shift = (16 - BIT_DEPTH) as i32;
104
105    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "sse"))]
106    let use_sse = std::arch::is_x86_feature_detected!("sse4.1");
107    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "avx"))]
108    let use_avx = std::arch::is_x86_feature_detected!("avx2");
109    #[cfg(all(
110        any(target_arch = "x86", target_arch = "x86_64"),
111        feature = "nightly_avx512"
112    ))]
113    let use_avx512 = std::arch::is_x86_feature_detected!("avx512bw");
114    #[cfg(all(
115        any(target_arch = "x86", target_arch = "x86_64"),
116        feature = "nightly_avx512"
117    ))]
118    let use_vbmi = std::arch::is_x86_feature_detected!("avx512vbmi");
119    #[cfg(all(
120        any(target_arch = "x86", target_arch = "x86_64"),
121        feature = "nightly_avx512"
122    ))]
123    let avx512_wide_row_handler = if use_vbmi {
124        avx512_yuv_p16_to_rgba8_row::<
125            DESTINATION_CHANNELS,
126            SAMPLING,
127            ENDIANNESS,
128            BYTES_POSITION,
129            BIT_DEPTH,
130            PRECISION,
131            true,
132        >
133    } else {
134        avx512_yuv_p16_to_rgba8_row::<
135            DESTINATION_CHANNELS,
136            SAMPLING,
137            ENDIANNESS,
138            BYTES_POSITION,
139            BIT_DEPTH,
140            PRECISION,
141            false,
142        >
143    };
144
145    #[inline(always)]
146    /// Saturating rounding shift right against bit depth
147    fn qrshr<const BIT_DEPTH: usize>(val: i32) -> i32 {
148        let total_shift = PRECISION + (BIT_DEPTH as i32 - 8);
149        let rounding: i32 = 1 << (total_shift - 1);
150        let max_value: i32 = (1 << BIT_DEPTH) - 1;
151        ((val + rounding) >> total_shift).min(max_value).max(0)
152    }
153
154    let process_wide_row =
155        |_y_plane: &[u16], _u_plane: &[u16], _v_plane: &[u16], _rgba: &mut [u8]| {
156            let mut _cx = 0usize;
157            #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
158            {
159                let mut _v_offset = ProcessedOffset { cx: 0, ux: 0 };
160                {
161                    #[cfg(feature = "nightly_avx512")]
162                    if use_avx512 {
163                        unsafe {
164                            let offset = avx512_wide_row_handler(
165                                _y_plane,
166                                _u_plane,
167                                _v_plane,
168                                _rgba,
169                                image.width,
170                                &chroma_range,
171                                &i_transform,
172                                _v_offset.cx,
173                                _v_offset.ux,
174                            );
175                            _v_offset = offset;
176                        }
177                    }
178                    #[cfg(feature = "avx")]
179                    if use_avx {
180                        use crate::avx2::avx_yuv_p16_to_rgba8_row;
181                        unsafe {
182                            let offset = avx_yuv_p16_to_rgba8_row::<
183                                DESTINATION_CHANNELS,
184                                SAMPLING,
185                                ENDIANNESS,
186                                BYTES_POSITION,
187                                BIT_DEPTH,
188                                PRECISION,
189                            >(
190                                _y_plane,
191                                _u_plane,
192                                _v_plane,
193                                _rgba,
194                                image.width,
195                                &chroma_range,
196                                &i_transform,
197                                _v_offset.cx,
198                                _v_offset.ux,
199                            );
200                            _v_offset = offset;
201                        }
202                    }
203                    #[cfg(feature = "sse")]
204                    if use_sse {
205                        use crate::sse::sse_yuv_p16_to_rgba8_row;
206                        unsafe {
207                            let offset = sse_yuv_p16_to_rgba8_row::<
208                                DESTINATION_CHANNELS,
209                                SAMPLING,
210                                ENDIANNESS,
211                                BYTES_POSITION,
212                                BIT_DEPTH,
213                                PRECISION,
214                            >(
215                                _y_plane,
216                                _u_plane,
217                                _v_plane,
218                                _rgba,
219                                image.width,
220                                &chroma_range,
221                                &i_transform,
222                                _v_offset.cx,
223                                _v_offset.ux,
224                            );
225                            _v_offset = offset;
226                        }
227                    }
228                }
229                _cx = _v_offset.cx;
230            }
231            #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
232            {
233                unsafe {
234                    let offset = neon_yuv_p16_to_rgba_row::<
235                        DESTINATION_CHANNELS,
236                        SAMPLING,
237                        ENDIANNESS,
238                        BYTES_POSITION,
239                        BIT_DEPTH,
240                        PRECISION,
241                    >(
242                        _y_plane,
243                        _u_plane,
244                        _v_plane,
245                        _rgba,
246                        0,
247                        image.width,
248                        &chroma_range,
249                        &i_transform,
250                        0,
251                        0,
252                    );
253                    _cx = offset.cx;
254                }
255            }
256            _cx
257        };
258
259    let process_halved_chroma_row = |y_plane: &[u16],
260                                     u_plane: &[u16],
261                                     v_plane: &[u16],
262                                     rgba: &mut [u8]| {
263        let cx = process_wide_row(y_plane, u_plane, v_plane, rgba);
264
265        for (((rgba, y_src), &u_src), &v_src) in rgba
266            .chunks_exact_mut(channels * 2)
267            .zip(y_plane.chunks_exact(2))
268            .zip(u_plane.iter())
269            .zip(v_plane.iter())
270            .skip(cx / 2)
271        {
272            let y_value0 =
273                (to_ne::<ENDIANNESS, BYTES_POSITION>(y_src[0], msb_shift) as i32 - bias_y) * y_coef;
274            let cb_value = to_ne::<ENDIANNESS, BYTES_POSITION>(u_src, msb_shift) as i32 - bias_uv;
275            let cr_value = to_ne::<ENDIANNESS, BYTES_POSITION>(v_src, msb_shift) as i32 - bias_uv;
276
277            let r0 = qrshr::<BIT_DEPTH>(y_value0 + cr_coef * cr_value);
278            let b0 = qrshr::<BIT_DEPTH>(y_value0 + cb_coef * cb_value);
279            let g0 = qrshr::<BIT_DEPTH>(y_value0 - g_coef_1 * cr_value - g_coef_2 * cb_value);
280
281            let rgba0 = &mut rgba[0..channels];
282
283            rgba0[dst_chans.get_r_channel_offset()] = r0 as u8;
284            rgba0[dst_chans.get_g_channel_offset()] = g0 as u8;
285            rgba0[dst_chans.get_b_channel_offset()] = b0 as u8;
286            if dst_chans.has_alpha() {
287                rgba0[dst_chans.get_a_channel_offset()] = 255;
288            }
289
290            let y_value1 =
291                (to_ne::<ENDIANNESS, BYTES_POSITION>(y_src[1], msb_shift) as i32 - bias_y) * y_coef;
292
293            let r1 = qrshr::<BIT_DEPTH>(y_value1 + cr_coef * cr_value);
294            let b1 = qrshr::<BIT_DEPTH>(y_value1 + cb_coef * cb_value);
295            let g1 = qrshr::<BIT_DEPTH>(y_value1 - g_coef_1 * cr_value - g_coef_2 * cb_value);
296
297            let rgba1 = &mut rgba[channels..channels * 2];
298
299            rgba1[dst_chans.get_r_channel_offset()] = r1 as u8;
300            rgba1[dst_chans.get_g_channel_offset()] = g1 as u8;
301            rgba1[dst_chans.get_b_channel_offset()] = b1 as u8;
302            if dst_chans.has_alpha() {
303                rgba1[dst_chans.get_a_channel_offset()] = 255;
304            }
305        }
306
307        if image.width & 1 != 0 {
308            let y_value0 = (to_ne::<ENDIANNESS, BYTES_POSITION>(*y_plane.last().unwrap(), msb_shift)
309                as i32
310                - bias_y)
311                * y_coef;
312            let cb_value = to_ne::<ENDIANNESS, BYTES_POSITION>(*u_plane.last().unwrap(), msb_shift)
313                as i32
314                - bias_uv;
315            let cr_value = to_ne::<ENDIANNESS, BYTES_POSITION>(*v_plane.last().unwrap(), msb_shift)
316                as i32
317                - bias_uv;
318            let rgba = rgba.chunks_exact_mut(channels).last().unwrap();
319            let rgba0 = &mut rgba[0..channels];
320
321            let r0 = qrshr::<BIT_DEPTH>(y_value0 + cr_coef * cr_value);
322            let b0 = qrshr::<BIT_DEPTH>(y_value0 + cb_coef * cb_value);
323            let g0 = qrshr::<BIT_DEPTH>(y_value0 - g_coef_1 * cr_value - g_coef_2 * cb_value);
324            rgba0[dst_chans.get_r_channel_offset()] = r0 as u8;
325            rgba0[dst_chans.get_g_channel_offset()] = g0 as u8;
326            rgba0[dst_chans.get_b_channel_offset()] = b0 as u8;
327            if dst_chans.has_alpha() {
328                rgba0[dst_chans.get_a_channel_offset()] = 255;
329            }
330        }
331    };
332
333    if chroma_subsampling == YuvChromaSubsampling::Yuv444 {
334        let iter;
335        #[cfg(feature = "rayon")]
336        {
337            iter = rgba
338                .par_chunks_exact_mut(rgba_stride as usize)
339                .zip(image.y_plane.par_chunks_exact(image.y_stride as usize))
340                .zip(image.u_plane.par_chunks_exact(image.u_stride as usize))
341                .zip(image.v_plane.par_chunks_exact(image.v_stride as usize));
342        }
343        #[cfg(not(feature = "rayon"))]
344        {
345            iter = rgba
346                .chunks_exact_mut(rgba_stride as usize)
347                .zip(image.y_plane.chunks_exact(image.y_stride as usize))
348                .zip(image.u_plane.chunks_exact(image.u_stride as usize))
349                .zip(image.v_plane.chunks_exact(image.v_stride as usize));
350        }
351        iter.for_each(|(((rgba, y_plane), u_plane), v_plane)| {
352            let y_plane = &y_plane[0..image.width as usize];
353            let cx = process_wide_row(y_plane, u_plane, v_plane, rgba);
354
355            for (((rgba, &y_src), &u_src), &v_src) in rgba
356                .chunks_exact_mut(channels)
357                .zip(y_plane.iter())
358                .zip(u_plane.iter())
359                .zip(v_plane.iter())
360                .skip(cx)
361            {
362                let y_value = (to_ne::<ENDIANNESS, BYTES_POSITION>(y_src, msb_shift) as i32
363                    - bias_y)
364                    * y_coef;
365                let cb_value =
366                    to_ne::<ENDIANNESS, BYTES_POSITION>(u_src, msb_shift) as i32 - bias_uv;
367                let cr_value =
368                    to_ne::<ENDIANNESS, BYTES_POSITION>(v_src, msb_shift) as i32 - bias_uv;
369
370                let r = qrshr::<BIT_DEPTH>(y_value + cr_coef * cr_value);
371                let b = qrshr::<BIT_DEPTH>(y_value + cb_coef * cb_value);
372                let g = qrshr::<BIT_DEPTH>(y_value - g_coef_1 * cr_value - g_coef_2 * cb_value);
373
374                rgba[dst_chans.get_r_channel_offset()] = r as u8;
375                rgba[dst_chans.get_g_channel_offset()] = g as u8;
376                rgba[dst_chans.get_b_channel_offset()] = b as u8;
377                if dst_chans.has_alpha() {
378                    rgba[dst_chans.get_a_channel_offset()] = 255;
379                }
380            }
381        });
382    } else if chroma_subsampling == YuvChromaSubsampling::Yuv422 {
383        let iter;
384        #[cfg(feature = "rayon")]
385        {
386            iter = rgba
387                .par_chunks_exact_mut(rgba_stride as usize)
388                .zip(image.y_plane.par_chunks_exact(image.y_stride as usize))
389                .zip(image.u_plane.par_chunks_exact(image.u_stride as usize))
390                .zip(image.v_plane.par_chunks_exact(image.v_stride as usize));
391        }
392        #[cfg(not(feature = "rayon"))]
393        {
394            iter = rgba
395                .chunks_exact_mut(rgba_stride as usize)
396                .zip(image.y_plane.chunks_exact(image.y_stride as usize))
397                .zip(image.u_plane.chunks_exact(image.u_stride as usize))
398                .zip(image.v_plane.chunks_exact(image.v_stride as usize));
399        }
400        iter.for_each(|(((rgba, y_plane), u_plane), v_plane)| {
401            process_halved_chroma_row(
402                &y_plane[0..image.width as usize],
403                &u_plane[0..(image.width as usize).div_ceil(2)],
404                &v_plane[0..(image.width as usize).div_ceil(2)],
405                &mut rgba[0..image.width as usize * channels],
406            );
407        });
408    } else if chroma_subsampling == YuvChromaSubsampling::Yuv420 {
409        let iter;
410        #[cfg(feature = "rayon")]
411        {
412            iter = rgba
413                .par_chunks_exact_mut(rgba_stride as usize * 2)
414                .zip(image.y_plane.par_chunks_exact(image.y_stride as usize * 2))
415                .zip(image.u_plane.par_chunks_exact(image.u_stride as usize))
416                .zip(image.v_plane.par_chunks_exact(image.v_stride as usize));
417        }
418        #[cfg(not(feature = "rayon"))]
419        {
420            iter = rgba
421                .chunks_exact_mut(rgba_stride as usize * 2)
422                .zip(image.y_plane.chunks_exact(image.y_stride as usize * 2))
423                .zip(image.u_plane.chunks_exact(image.u_stride as usize))
424                .zip(image.v_plane.chunks_exact(image.v_stride as usize));
425        }
426        iter.for_each(|(((rgba, y_plane), u_plane), v_plane)| {
427            for (rgba, y_plane) in rgba
428                .chunks_exact_mut(rgba_stride as usize)
429                .zip(y_plane.chunks_exact(image.y_stride as usize))
430            {
431                process_halved_chroma_row(
432                    &y_plane[0..image.width as usize],
433                    &u_plane[0..(image.width as usize).div_ceil(2)],
434                    &v_plane[0..(image.width as usize).div_ceil(2)],
435                    &mut rgba[0..image.width as usize * channels],
436                );
437            }
438        });
439
440        if image.height & 1 != 0 {
441            let rgba = rgba.chunks_exact_mut(rgba_stride as usize).last().unwrap();
442            let u_plane = image
443                .u_plane
444                .chunks_exact(image.u_stride as usize)
445                .last()
446                .unwrap();
447            let v_plane = image
448                .v_plane
449                .chunks_exact(image.v_stride as usize)
450                .last()
451                .unwrap();
452            let y_plane = image
453                .y_plane
454                .chunks_exact(image.y_stride as usize)
455                .last()
456                .unwrap();
457            process_halved_chroma_row(
458                &y_plane[0..image.width as usize],
459                &u_plane[0..(image.width as usize).div_ceil(2)],
460                &v_plane[0..(image.width as usize).div_ceil(2)],
461                &mut rgba[0..image.width as usize * channels],
462            );
463        }
464    } else {
465        unreachable!();
466    }
467
468    Ok(())
469}
470
471macro_rules! build_cnv {
472    ($method: ident, $sampling: expr, $px_fmt: expr, $bit_depth: expr, $sampling_written: expr, $px_written: expr, $px_written_small: expr, $endian: expr) => {
473        #[doc = concat!("
474Convert ",$sampling_written, " planar format with ", $bit_depth," bit pixel format to ", $px_written," 8-bit format.
475
476This function takes ", $sampling_written, " planar data with ",$bit_depth," bit precision.
477and converts it to ", $px_written," format with 8 bit-depth precision per channel
478
479# Arguments
480
481* `planar_image` - Source ",$sampling_written," planar image.
482* `", $px_written_small, "` - A mutable slice to store the converted ", $px_written," 8 bit-depth format.
483* `", $px_written_small, "_stride` - The stride (components per row) for ", $px_written," 8 bit-depth format.
484* `range` - The YUV range (limited or full).
485* `matrix` - The YUV standard matrix (BT.601 or BT.709 or BT.2020 or other).
486
487# Panics
488
489This function panics if the lengths of the planes or the input ", $px_written," data are not valid based
490on the specified width, height, and strides, or if invalid YUV range or matrix is provided.")]
491        pub fn $method(
492            planar_image: &YuvPlanarImage<u16>,
493            dst: &mut [u8],
494            dst_stride: u32,
495            range: YuvRange,
496            matrix: YuvStandardMatrix,
497        ) -> Result<(), YuvError> {
498             yuv_p16_to_image_ant::<{ $px_fmt as u8 }, { $sampling as u8 }, { $endian as u8 }, { YuvBytesPacking::LeastSignificantBytes as u8 }, $bit_depth>(
499                planar_image,
500                dst,
501                dst_stride,
502                range,
503                matrix,
504             )
505        }
506    };
507}
508
509build_cnv!(
510    i010_to_rgba,
511    YuvChromaSubsampling::Yuv420,
512    YuvSourceChannels::Rgba,
513    10,
514    "YUV 420 10-bit",
515    "RGBA",
516    "rgba",
517    YuvEndianness::LittleEndian
518);
519#[cfg(feature = "big_endian")]
520build_cnv!(
521    i010_be_to_rgba,
522    YuvChromaSubsampling::Yuv420,
523    YuvSourceChannels::Rgba,
524    10,
525    "YUV 420 10-bit",
526    "RGBA",
527    "rgba",
528    YuvEndianness::BigEndian
529);
530
531build_cnv!(
532    i010_to_bgra,
533    YuvChromaSubsampling::Yuv420,
534    YuvSourceChannels::Bgra,
535    10,
536    "YUV 420 10-bit",
537    "BGRA",
538    "bgra",
539    YuvEndianness::LittleEndian
540);
541#[cfg(feature = "big_endian")]
542build_cnv!(
543    i010_be_to_bgra,
544    YuvChromaSubsampling::Yuv420,
545    YuvSourceChannels::Rgba,
546    10,
547    "YUV 420 10-bit",
548    "BGRA",
549    "bgra",
550    YuvEndianness::BigEndian
551);
552
553build_cnv!(
554    i010_to_rgb,
555    YuvChromaSubsampling::Yuv420,
556    YuvSourceChannels::Rgb,
557    10,
558    "YUV 420 10-bit",
559    "RGB",
560    "rgb",
561    YuvEndianness::LittleEndian
562);
563#[cfg(feature = "big_endian")]
564build_cnv!(
565    i010_be_to_rgb,
566    YuvChromaSubsampling::Yuv420,
567    YuvSourceChannels::Rgb,
568    10,
569    "YUV 420 10-bit",
570    "RGB",
571    "rgb",
572    YuvEndianness::BigEndian
573);
574
575build_cnv!(
576    i010_to_bgr,
577    YuvChromaSubsampling::Yuv420,
578    YuvSourceChannels::Bgr,
579    10,
580    "YUV 420 10-bit",
581    "BGR",
582    "bgr",
583    YuvEndianness::LittleEndian
584);
585#[cfg(feature = "big_endian")]
586build_cnv!(
587    i010_be_to_bgr,
588    YuvChromaSubsampling::Yuv420,
589    YuvSourceChannels::Bgr,
590    10,
591    "YUV 420 10-bit",
592    "BGR",
593    "bgr",
594    YuvEndianness::BigEndian
595);
596
597build_cnv!(
598    i210_to_rgba,
599    YuvChromaSubsampling::Yuv422,
600    YuvSourceChannels::Rgba,
601    10,
602    "YUV 420 10-bit",
603    "RGBA",
604    "rgba",
605    YuvEndianness::LittleEndian
606);
607#[cfg(feature = "big_endian")]
608build_cnv!(
609    i210_be_to_rgba,
610    YuvChromaSubsampling::Yuv422,
611    YuvSourceChannels::Rgba,
612    10,
613    "YUV 420 10-bit",
614    "RGBA",
615    "rgba",
616    YuvEndianness::BigEndian
617);
618
619build_cnv!(
620    i210_to_bgra,
621    YuvChromaSubsampling::Yuv422,
622    YuvSourceChannels::Bgra,
623    10,
624    "YUV 420 10-bit",
625    "BGRA",
626    "bgra",
627    YuvEndianness::LittleEndian
628);
629#[cfg(feature = "big_endian")]
630build_cnv!(
631    i210_be_to_bgra,
632    YuvChromaSubsampling::Yuv422,
633    YuvSourceChannels::Rgba,
634    10,
635    "YUV 420 10-bit",
636    "BGRA",
637    "bgra",
638    YuvEndianness::BigEndian
639);
640
641build_cnv!(
642    i210_to_rgb,
643    YuvChromaSubsampling::Yuv422,
644    YuvSourceChannels::Rgb,
645    10,
646    "YUV 420 10-bit",
647    "RGB",
648    "rgb",
649    YuvEndianness::LittleEndian
650);
651#[cfg(feature = "big_endian")]
652build_cnv!(
653    i210_be_to_rgb,
654    YuvChromaSubsampling::Yuv422,
655    YuvSourceChannels::Rgb,
656    10,
657    "YUV 420 10-bit",
658    "RGB",
659    "rgb",
660    YuvEndianness::BigEndian
661);
662
663build_cnv!(
664    i210_to_bgr,
665    YuvChromaSubsampling::Yuv422,
666    YuvSourceChannels::Bgr,
667    10,
668    "YUV 420 10-bit",
669    "BGR",
670    "bgr",
671    YuvEndianness::LittleEndian
672);
673#[cfg(feature = "big_endian")]
674build_cnv!(
675    i210_be_to_bgr,
676    YuvChromaSubsampling::Yuv422,
677    YuvSourceChannels::Bgr,
678    10,
679    "YUV 420 10-bit",
680    "BGR",
681    "bgr",
682    YuvEndianness::BigEndian
683);
684
685build_cnv!(
686    i012_to_rgba,
687    YuvChromaSubsampling::Yuv420,
688    YuvSourceChannels::Rgba,
689    12,
690    "YUV 420 12-bit",
691    "RGBA",
692    "rgba",
693    YuvEndianness::LittleEndian
694);
695#[cfg(feature = "big_endian")]
696build_cnv!(
697    i012_be_to_rgba,
698    YuvChromaSubsampling::Yuv420,
699    YuvSourceChannels::Rgba,
700    12,
701    "YUV 420 12-bit",
702    "RGBA",
703    "rgba",
704    YuvEndianness::BigEndian
705);
706
707build_cnv!(
708    i012_to_bgra,
709    YuvChromaSubsampling::Yuv420,
710    YuvSourceChannels::Bgra,
711    12,
712    "YUV 420 12-bit",
713    "BGRA",
714    "bgra",
715    YuvEndianness::LittleEndian
716);
717#[cfg(feature = "big_endian")]
718build_cnv!(
719    i012_be_to_bgra,
720    YuvChromaSubsampling::Yuv420,
721    YuvSourceChannels::Rgba,
722    12,
723    "YUV 420 12-bit",
724    "BGRA",
725    "bgra",
726    YuvEndianness::BigEndian
727);
728
729build_cnv!(
730    i012_to_rgb,
731    YuvChromaSubsampling::Yuv420,
732    YuvSourceChannels::Rgb,
733    12,
734    "YUV 420 12-bit",
735    "RGB",
736    "rgb",
737    YuvEndianness::LittleEndian
738);
739#[cfg(feature = "big_endian")]
740build_cnv!(
741    i012_be_to_rgb,
742    YuvChromaSubsampling::Yuv420,
743    YuvSourceChannels::Rgb,
744    12,
745    "YUV 420 12-bit",
746    "RGB",
747    "rgb",
748    YuvEndianness::BigEndian
749);
750
751build_cnv!(
752    i012_to_bgr,
753    YuvChromaSubsampling::Yuv420,
754    YuvSourceChannels::Bgr,
755    12,
756    "YUV 420 12-bit",
757    "BGR",
758    "bgr",
759    YuvEndianness::LittleEndian
760);
761#[cfg(feature = "big_endian")]
762build_cnv!(
763    i012_be_to_bgr,
764    YuvChromaSubsampling::Yuv420,
765    YuvSourceChannels::Bgr,
766    12,
767    "YUV 420 12-bit",
768    "BGR",
769    "bgr",
770    YuvEndianness::BigEndian
771);
772
773build_cnv!(
774    i212_to_rgba,
775    YuvChromaSubsampling::Yuv422,
776    YuvSourceChannels::Rgba,
777    12,
778    "YUV 420 12-bit",
779    "RGBA",
780    "rgba",
781    YuvEndianness::LittleEndian
782);
783#[cfg(feature = "big_endian")]
784build_cnv!(
785    i212_be_to_rgba,
786    YuvChromaSubsampling::Yuv422,
787    YuvSourceChannels::Rgba,
788    12,
789    "YUV 420 12-bit",
790    "RGBA",
791    "rgba",
792    YuvEndianness::BigEndian
793);
794
795build_cnv!(
796    i212_to_bgra,
797    YuvChromaSubsampling::Yuv422,
798    YuvSourceChannels::Bgra,
799    12,
800    "YUV 420 12-bit",
801    "BGRA",
802    "bgra",
803    YuvEndianness::LittleEndian
804);
805#[cfg(feature = "big_endian")]
806build_cnv!(
807    i212_be_to_bgra,
808    YuvChromaSubsampling::Yuv422,
809    YuvSourceChannels::Rgba,
810    12,
811    "YUV 420 12-bit",
812    "BGRA",
813    "bgra",
814    YuvEndianness::BigEndian
815);
816
817build_cnv!(
818    i212_to_rgb,
819    YuvChromaSubsampling::Yuv422,
820    YuvSourceChannels::Rgb,
821    12,
822    "YUV 420 12-bit",
823    "RGB",
824    "rgb",
825    YuvEndianness::LittleEndian
826);
827#[cfg(feature = "big_endian")]
828build_cnv!(
829    i212_be_to_rgb,
830    YuvChromaSubsampling::Yuv422,
831    YuvSourceChannels::Rgb,
832    12,
833    "YUV 420 12-bit",
834    "RGB",
835    "rgb",
836    YuvEndianness::BigEndian
837);
838
839build_cnv!(
840    i212_to_bgr,
841    YuvChromaSubsampling::Yuv422,
842    YuvSourceChannels::Bgr,
843    12,
844    "YUV 420 12-bit",
845    "BGR",
846    "bgr",
847    YuvEndianness::LittleEndian
848);
849#[cfg(feature = "big_endian")]
850build_cnv!(
851    i212_be_to_bgr,
852    YuvChromaSubsampling::Yuv422,
853    YuvSourceChannels::Bgr,
854    12,
855    "YUV 420 12-bit",
856    "BGR",
857    "bgr",
858    YuvEndianness::BigEndian
859);
860
861build_cnv!(
862    i410_to_rgba,
863    YuvChromaSubsampling::Yuv444,
864    YuvSourceChannels::Rgba,
865    10,
866    "YUV 444 10-bit",
867    "RGBA",
868    "rgba",
869    YuvEndianness::LittleEndian
870);
871#[cfg(feature = "big_endian")]
872build_cnv!(
873    i410_be_to_rgba,
874    YuvChromaSubsampling::Yuv444,
875    YuvSourceChannels::Rgba,
876    10,
877    "YUV 444 10-bit",
878    "RGBA",
879    "rgba",
880    YuvEndianness::BigEndian
881);