1#[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 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);