yuvutils_rs/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#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
30use crate::neon::yuv_to_yuy2_neon_impl;
31
32use crate::yuv_support::{YuvChromaSubsampling, Yuy2Description};
33use crate::{YuvError, YuvPackedImageMut, YuvPlanarImage};
34#[cfg(feature = "rayon")]
35use rayon::iter::{IndexedParallelIterator, ParallelIterator};
36#[cfg(feature = "rayon")]
37use rayon::prelude::{ParallelSlice, ParallelSliceMut};
38use std::fmt::Debug;
39
40#[allow(dead_code)]
41#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
42pub struct YuvToYuy2Navigation {
43 pub cx: usize,
44 pub uv_x: usize,
45 pub x: usize,
46}
47
48impl YuvToYuy2Navigation {
49 #[allow(dead_code)]
50 pub const fn new(cx: usize, uv_x: usize, x: usize) -> YuvToYuy2Navigation {
51 YuvToYuy2Navigation { cx, uv_x, x }
52 }
53}
54
55pub(crate) trait AveragesIntensity<V> {
56 fn averages(self, other: V) -> V;
57}
58
59impl AveragesIntensity<u8> for u8 {
60 #[inline(always)]
61 fn averages(self, other: u8) -> u8 {
62 ((self as u16 + other as u16 + 1) >> 1) as u8
63 }
64}
65
66impl AveragesIntensity<u16> for u16 {
67 #[inline(always)]
68 fn averages(self, other: u16) -> u16 {
69 ((self as u32 + other as u32 + 1) >> 1) as u16
70 }
71}
72
73pub(crate) trait ProcessWideRow<V> {
74 fn process_wide_row<const SAMPLING: u8, const YUY2_TARGET: usize>(
75 yuy2: &mut [V],
76 y_src: &[V],
77 u_src: &[V],
78 v_src: &[V],
79 width: usize,
80 ) -> usize;
81}
82
83impl ProcessWideRow<u8> for u8 {
84 fn process_wide_row<const SAMPLING: u8, const YUY2_TARGET: usize>(
85 _yuy2: &mut [u8],
86 _y_src: &[u8],
87 _u_src: &[u8],
88 _v_src: &[u8],
89 _width: usize,
90 ) -> usize {
91 let mut _processed = 0usize;
92
93 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "sse"))]
94 let _use_sse = is_x86_feature_detected!("sse4.1");
95 #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), feature = "avx"))]
96 let _use_avx2 = is_x86_feature_detected!("avx2");
97
98 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
99 {
100 let mut _nav = YuvToYuy2Navigation::new(0, 0, 0);
101 #[cfg(feature = "avx")]
102 if _use_avx2 {
103 use crate::avx2::yuv_to_yuy2_avx2_row;
104 _nav = yuv_to_yuy2_avx2_row::<SAMPLING, YUY2_TARGET>(
105 _y_src,
106 _u_src,
107 _v_src,
108 _yuy2,
109 _width as u32,
110 _nav,
111 );
112 }
113 #[cfg(feature = "sse")]
114 if _use_sse {
115 use crate::sse::yuv_to_yuy2_sse;
116 _nav = yuv_to_yuy2_sse::<SAMPLING, YUY2_TARGET>(
117 _y_src,
118 _u_src,
119 _v_src,
120 _yuy2,
121 _width as u32,
122 _nav,
123 );
124 }
125 _processed = _nav.cx;
126 }
127
128 #[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
129 {
130 let processed = yuv_to_yuy2_neon_impl::<SAMPLING, YUY2_TARGET>(
131 _y_src,
132 _u_src,
133 _v_src,
134 _yuy2,
135 _width as u32,
136 YuvToYuy2Navigation::new(0, 0, 0),
137 );
138 _processed = processed.cx;
139 }
140 _processed
141 }
142}
143
144impl ProcessWideRow<u16> for u16 {
145 fn process_wide_row<const SAMPLING: u8, const YUY2_TARGET: usize>(
146 _: &mut [u16],
147 _: &[u16],
148 _: &[u16],
149 _: &[u16],
150 _: usize,
151 ) -> usize {
152 0
153 }
154}
155
156pub(crate) fn yuv_to_yuy2_impl<
157 V: Copy + Debug + Send + Sync + AveragesIntensity<V> + Default + ProcessWideRow<V>,
158 const SAMPLING: u8,
159 const YUY2_TARGET: usize,
160>(
161 planar_image: &YuvPlanarImage<V>,
162 image: &mut YuvPackedImageMut<V>,
163) -> Result<(), YuvError> {
164 let yuy2_target: Yuy2Description = YUY2_TARGET.into();
165 let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into();
166
167 planar_image.check_constraints(chroma_subsampling)?;
168 image.check_constraints()?;
169 if planar_image.width != image.width || planar_image.height != image.height {
170 return Err(YuvError::ImagesSizesNotMatch);
171 }
172
173 let yuy2_width = if planar_image.width % 2 == 0 {
174 2 * planar_image.width as usize
175 } else {
176 2 * (planar_image.width as usize + 1)
177 };
178
179 let width = planar_image.width;
180
181 if chroma_subsampling == YuvChromaSubsampling::Yuv444 {
182 let iter;
183 #[cfg(feature = "rayon")]
184 {
185 iter = image
186 .yuy
187 .borrow_mut()
188 .par_chunks_exact_mut(image.yuy_stride as usize)
189 .zip(
190 planar_image
191 .y_plane
192 .par_chunks_exact(planar_image.y_stride as usize),
193 )
194 .zip(
195 planar_image
196 .u_plane
197 .par_chunks_exact(planar_image.u_stride as usize),
198 )
199 .zip(
200 planar_image
201 .v_plane
202 .par_chunks_exact(planar_image.v_stride as usize),
203 );
204 }
205 #[cfg(not(feature = "rayon"))]
206 {
207 iter = image
208 .yuy
209 .borrow_mut()
210 .chunks_exact_mut(image.yuy_stride as usize)
211 .zip(
212 planar_image
213 .y_plane
214 .chunks_exact(planar_image.y_stride as usize),
215 )
216 .zip(
217 planar_image
218 .u_plane
219 .chunks_exact(planar_image.u_stride as usize),
220 )
221 .zip(
222 planar_image
223 .v_plane
224 .chunks_exact(planar_image.v_stride as usize),
225 );
226 }
227
228 iter.for_each(|(((yuy2, y_src), u_src), v_src)| {
229 let yuy2 = &mut yuy2[0..yuy2_width];
230 let y_src = &y_src[0..image.width as usize];
231 let u_src = &u_src[0..image.width as usize];
232 let v_src = &v_src[0..image.width as usize];
233 let processed = V::process_wide_row::<SAMPLING, YUY2_TARGET>(
234 yuy2,
235 y_src,
236 u_src,
237 v_src,
238 width as usize,
239 );
240
241 for (((yuy2, y_src), u_src), v_src) in yuy2
242 .chunks_exact_mut(4)
243 .zip(y_src.chunks_exact(2))
244 .zip(u_src.chunks_exact(2))
245 .zip(v_src.chunks_exact(2))
246 .skip(processed)
247 {
248 yuy2[yuy2_target.get_first_y_position()] = y_src[0];
249 yuy2[yuy2_target.get_second_y_position()] = y_src[1];
250 yuy2[yuy2_target.get_u_position()] = u_src[0].averages(u_src[1]);
251 yuy2[yuy2_target.get_v_position()] = v_src[0].averages(v_src[1]);
252 }
253
254 if width & 1 != 0 {
255 let yuy2 = yuy2.chunks_exact_mut(4).last().unwrap();
256 let yuy2 = &mut yuy2[0..4];
257 let last_y = y_src.last().unwrap();
258 let last_u = u_src.last().unwrap();
259 let last_v = v_src.last().unwrap();
260 yuy2[yuy2_target.get_first_y_position()] = *last_y;
261 yuy2[yuy2_target.get_u_position()] = *last_u;
262 yuy2[yuy2_target.get_second_y_position()] = V::default();
263 yuy2[yuy2_target.get_v_position()] = *last_v;
264 }
265 });
266 } else if chroma_subsampling == YuvChromaSubsampling::Yuv422 {
267 let iter;
268 #[cfg(feature = "rayon")]
269 {
270 iter = image
271 .yuy
272 .borrow_mut()
273 .par_chunks_exact_mut(image.yuy_stride as usize)
274 .zip(
275 planar_image
276 .y_plane
277 .par_chunks_exact(planar_image.y_stride as usize),
278 )
279 .zip(
280 planar_image
281 .u_plane
282 .par_chunks_exact(planar_image.u_stride as usize),
283 )
284 .zip(
285 planar_image
286 .v_plane
287 .par_chunks_exact(planar_image.v_stride as usize),
288 );
289 }
290 #[cfg(not(feature = "rayon"))]
291 {
292 iter = image
293 .yuy
294 .borrow_mut()
295 .chunks_exact_mut(image.yuy_stride as usize)
296 .zip(
297 planar_image
298 .y_plane
299 .chunks_exact(planar_image.y_stride as usize),
300 )
301 .zip(
302 planar_image
303 .u_plane
304 .chunks_exact(planar_image.u_stride as usize),
305 )
306 .zip(
307 planar_image
308 .v_plane
309 .chunks_exact(planar_image.v_stride as usize),
310 );
311 }
312
313 iter.for_each(|(((yuy2, y_src), u_src), v_src)| {
314 let yuy2 = &mut yuy2[0..yuy2_width];
315 let y_src = &y_src[0..image.width as usize];
316 let u_src = &u_src[0..(image.width as usize).div_ceil(2)];
317 let v_src = &v_src[0..(image.width as usize).div_ceil(2)];
318
319 let processed = V::process_wide_row::<SAMPLING, YUY2_TARGET>(
320 yuy2,
321 y_src,
322 u_src,
323 v_src,
324 width as usize,
325 );
326
327 for (((yuy2, y_src), u_src), v_src) in yuy2
328 .chunks_exact_mut(4)
329 .zip(y_src.chunks_exact(2))
330 .zip(u_src.iter())
331 .zip(v_src.iter())
332 .skip(processed / 2)
333 {
334 yuy2[yuy2_target.get_first_y_position()] = y_src[0];
335 yuy2[yuy2_target.get_second_y_position()] = y_src[1];
336 yuy2[yuy2_target.get_u_position()] = *u_src;
337 yuy2[yuy2_target.get_v_position()] = *v_src;
338 }
339
340 if width & 1 != 0 {
341 let yuy2 = yuy2.chunks_exact_mut(4).last().unwrap();
342 let yuy2 = &mut yuy2[0..4];
343 let last_y = y_src.last().unwrap();
344 let last_u = u_src.last().unwrap();
345 let last_v = v_src.last().unwrap();
346 yuy2[yuy2_target.get_first_y_position()] = *last_y;
347 yuy2[yuy2_target.get_u_position()] = *last_u;
348 yuy2[yuy2_target.get_second_y_position()] = V::default();
349 yuy2[yuy2_target.get_v_position()] = *last_v;
350 }
351 });
352 } else if chroma_subsampling == YuvChromaSubsampling::Yuv420 {
353 let iter;
354 #[cfg(feature = "rayon")]
355 {
356 iter = image
357 .yuy
358 .borrow_mut()
359 .par_chunks_exact_mut(image.yuy_stride as usize * 2)
360 .zip(
361 planar_image
362 .y_plane
363 .par_chunks_exact(planar_image.y_stride as usize * 2),
364 )
365 .zip(
366 planar_image
367 .u_plane
368 .par_chunks_exact(planar_image.u_stride as usize),
369 )
370 .zip(
371 planar_image
372 .v_plane
373 .par_chunks_exact(planar_image.v_stride as usize),
374 );
375 }
376 #[cfg(not(feature = "rayon"))]
377 {
378 iter = image
379 .yuy
380 .borrow_mut()
381 .chunks_exact_mut(image.yuy_stride as usize * 2)
382 .zip(
383 planar_image
384 .y_plane
385 .chunks_exact(planar_image.y_stride as usize * 2),
386 )
387 .zip(
388 planar_image
389 .u_plane
390 .chunks_exact(planar_image.u_stride as usize),
391 )
392 .zip(
393 planar_image
394 .v_plane
395 .chunks_exact(planar_image.v_stride as usize),
396 );
397 }
398
399 iter.for_each(|(((yuy2, y_src), u_src), v_src)| {
400 for (yuy2, y_src) in yuy2
401 .chunks_exact_mut(image.yuy_stride as usize)
402 .zip(y_src.chunks_exact(planar_image.y_stride as usize))
403 {
404 let yuy2 = &mut yuy2[0..yuy2_width];
405 let y_src = &y_src[0..image.width as usize];
406 let u_src = &u_src[0..(image.width as usize).div_ceil(2)];
407 let v_src = &v_src[0..(image.width as usize).div_ceil(2)];
408
409 let processed = V::process_wide_row::<SAMPLING, YUY2_TARGET>(
410 yuy2,
411 y_src,
412 u_src,
413 v_src,
414 width as usize,
415 );
416
417 for (((yuy2, y_src), u_src), v_src) in yuy2
418 .chunks_exact_mut(4)
419 .zip(y_src.chunks_exact(2))
420 .zip(u_src.iter())
421 .zip(v_src.iter())
422 .skip(processed / 2)
423 {
424 yuy2[yuy2_target.get_first_y_position()] = y_src[0];
425 yuy2[yuy2_target.get_second_y_position()] = y_src[1];
426 yuy2[yuy2_target.get_u_position()] = *u_src;
427 yuy2[yuy2_target.get_v_position()] = *v_src;
428 }
429
430 if width & 1 != 0 {
431 let yuy2 = yuy2.chunks_exact_mut(4).last().unwrap();
432 let yuy2 = &mut yuy2[0..4];
433 let last_y = y_src.last().unwrap();
434 let last_u = u_src.last().unwrap();
435 let last_v = v_src.last().unwrap();
436 yuy2[yuy2_target.get_first_y_position()] = *last_y;
437 yuy2[yuy2_target.get_u_position()] = *last_u;
438 yuy2[yuy2_target.get_second_y_position()] = V::default();
439 yuy2[yuy2_target.get_v_position()] = *last_v;
440 }
441 }
442 });
443
444 if planar_image.height & 1 != 0 {
445 let rem_yuy = image
446 .yuy
447 .borrow_mut()
448 .chunks_exact_mut(image.yuy_stride as usize * 2)
449 .into_remainder();
450 let rem_y = planar_image
451 .y_plane
452 .chunks_exact(planar_image.y_stride as usize * 2)
453 .remainder();
454 let last_u = planar_image
455 .u_plane
456 .chunks_exact(planar_image.u_stride as usize)
457 .last()
458 .unwrap();
459 let last_v = planar_image
460 .v_plane
461 .chunks_exact(planar_image.v_stride as usize)
462 .last()
463 .unwrap();
464
465 let processed = V::process_wide_row::<SAMPLING, YUY2_TARGET>(
466 rem_yuy,
467 rem_y,
468 last_u,
469 last_v,
470 width as usize,
471 );
472
473 let rem_yuy = &mut rem_yuy[0..yuy2_width];
474 let rem_y = &rem_y[0..image.width as usize];
475 let last_u = &last_u[0..(image.width as usize).div_ceil(2)];
476 let last_v = &last_v[0..(image.width as usize).div_ceil(2)];
477
478 for (((yuy2, y_src), u_src), v_src) in rem_yuy
479 .chunks_exact_mut(4)
480 .zip(rem_y.chunks_exact(2))
481 .zip(last_u.iter())
482 .zip(last_v.iter())
483 .skip(processed / 2)
484 {
485 yuy2[yuy2_target.get_first_y_position()] = y_src[0];
486 yuy2[yuy2_target.get_second_y_position()] = y_src[1];
487 yuy2[yuy2_target.get_u_position()] = *u_src;
488 yuy2[yuy2_target.get_v_position()] = *v_src;
489 }
490
491 if width & 1 != 0 {
492 let yuy2 = rem_yuy.chunks_exact_mut(4).last().unwrap();
493 let yuy2 = &mut yuy2[0..4];
494 let last_y = rem_y.last().unwrap();
495 let last_u = last_u.last().unwrap();
496 let last_v = last_v.last().unwrap();
497 yuy2[yuy2_target.get_first_y_position()] = *last_y;
498 yuy2[yuy2_target.get_u_position()] = *last_u;
499 yuy2[yuy2_target.get_second_y_position()] = V::default();
500 yuy2[yuy2_target.get_v_position()] = *last_v;
501 }
502 }
503 } else {
504 unreachable!();
505 }
506 Ok(())
507}
508
509/// Convert YUV 444 planar format to YUYV ( YUV Packed ) format.
510///
511/// This function takes YUV 444 planar format data with 8-bit precision,
512/// and converts it to YUYV format with 8-bit per channel precision.
513/// Do not forget about odd alignment, use (width + 1) for buffers.
514///
515/// # Arguments
516///
517/// * `packed_image` - Target packed frame image.
518/// * `planar_image` - Source planar image.
519///
520/// # Panics
521///
522/// This function panics if the lengths of the planes or the input YUYV data are not valid based
523/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
524/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
525///
526pub fn yuv444_to_yuyv422(
527 packed_image: &mut YuvPackedImageMut<u8>,
528 planar_image: &YuvPlanarImage<u8>,
529) -> Result<(), YuvError> {
530 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv444 as u8 }, { Yuy2Description::YUYV as usize }>(
531 planar_image,
532 packed_image,
533 )
534}
535
536/// Convert YUV 422 planar format to YUYV ( YUV Packed ) format.
537///
538/// This function takes YUV 422 planar format data with 8-bit precision,
539/// and converts it to YUYV format with 8-bit per channel precision.
540/// Do not forget about odd alignment, use (width + 1) for buffers.
541///
542/// # Arguments
543///
544/// * `packed_image` - Target packed frame image.
545/// * `planar_image` - Source planar image.
546///
547/// # Panics
548///
549/// This function panics if the lengths of the planes or the input YUYV data are not valid based
550/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
551/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
552///
553pub fn yuv422_to_yuyv422(
554 packed_image: &mut YuvPackedImageMut<u8>,
555 planar_image: &YuvPlanarImage<u8>,
556) -> Result<(), YuvError> {
557 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv422 as u8 }, { Yuy2Description::YUYV as usize }>(
558 planar_image,
559 packed_image,
560 )
561}
562
563/// Convert YUV 420 planar format to YUYV ( YUV Packed ) format.
564///
565/// This function takes YUV 420 planar format data with 8-bit precision,
566/// and converts it to YUYV format with 8-bit per channel precision.
567/// Do not forget about odd alignment, use (width + 1) for buffers.
568///
569/// # Arguments
570///
571/// * `packed_image` - Target packed frame image.
572/// * `planar_image` - Source planar image.
573///
574/// # Panics
575///
576/// This function panics if the lengths of the planes or the input YUYV data are not valid based
577/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
578/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
579///
580pub fn yuv420_to_yuyv422(
581 packed_image: &mut YuvPackedImageMut<u8>,
582 planar_image: &YuvPlanarImage<u8>,
583) -> Result<(), YuvError> {
584 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv420 as u8 }, { Yuy2Description::YUYV as usize }>(
585 planar_image,
586 packed_image,
587 )
588}
589
590/// Convert YUV 444 planar format to YVYU ( YUV Packed ) format.
591///
592/// This function takes YUV 444 planar format data with 8-bit precision,
593/// and converts it to YVYU format with 8-bit per channel precision.
594/// Do not forget about odd alignment, use (width + 1) for buffers.
595///
596/// # Arguments
597///
598/// * `packed_image` - Target packed frame image.
599/// * `planar_image` - Source planar image.
600///
601/// # Panics
602///
603/// This function panics if the lengths of the planes or the input YVYU data are not valid based
604/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
605/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
606///
607pub fn yuv444_to_yvyu422(
608 packed_image: &mut YuvPackedImageMut<u8>,
609 planar_image: &YuvPlanarImage<u8>,
610) -> Result<(), YuvError> {
611 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv444 as u8 }, { Yuy2Description::YVYU as usize }>(
612 planar_image,
613 packed_image,
614 )
615}
616
617/// Convert YUV 422 planar format to YVYU ( YUV Packed ) format.
618///
619/// This function takes YUV 422 planar format data with 8-bit precision,
620/// and converts it to YVYU format with 8-bit per channel precision.
621/// Do not forget about odd alignment, use (width + 1) for buffers.
622///
623/// # Arguments
624///
625/// * `packed_image` - Target packed frame image.
626/// * `planar_image` - Source planar image.
627///
628/// # Panics
629///
630/// This function panics if the lengths of the planes or the input YVYU data are not valid based
631/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
632/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
633///
634pub fn yuv422_to_yvyu422(
635 packed_image: &mut YuvPackedImageMut<u8>,
636 planar_image: &YuvPlanarImage<u8>,
637) -> Result<(), YuvError> {
638 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv422 as u8 }, { Yuy2Description::YVYU as usize }>(
639 planar_image,
640 packed_image,
641 )
642}
643
644/// Convert YUV 420 planar format to YVYU ( YUV Packed ) format.
645///
646/// This function takes YUV 420 planar format data with 8-bit precision,
647/// and converts it to YVYU format with 8-bit per channel precision.
648/// Do not forget about odd alignment, use (width + 1) for buffers.
649///
650/// # Arguments
651///
652/// * `packed_image` - Target packed frame image.
653/// * `planar_image` - Source planar image.
654///
655/// # Panics
656///
657/// This function panics if the lengths of the planes or the input YVYU data are not valid based
658/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
659/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
660///
661pub fn yuv420_to_yvyu422(
662 packed_image: &mut YuvPackedImageMut<u8>,
663 planar_image: &YuvPlanarImage<u8>,
664) -> Result<(), YuvError> {
665 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv420 as u8 }, { Yuy2Description::YVYU as usize }>(
666 planar_image,
667 packed_image,
668 )
669}
670
671/// Convert YUV 444 planar format to VYUY ( YUV Packed ) format.
672///
673/// This function takes YUV 444 planar format data with 8-bit precision,
674/// and converts it to VYUY format with 8-bit per channel precision.
675/// Do not forget about odd alignment, use (width + 1) for buffers.
676///
677/// # Arguments
678///
679/// * `packed_image` - Target packed frame image.
680/// * `planar_image` - Source planar image.
681///
682/// # Panics
683///
684/// This function panics if the lengths of the planes or the input VYUY data are not valid based
685/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
686/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
687///
688pub fn yuv444_to_vyuy422(
689 packed_image: &mut YuvPackedImageMut<u8>,
690 planar_image: &YuvPlanarImage<u8>,
691) -> Result<(), YuvError> {
692 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv444 as u8 }, { Yuy2Description::VYUY as usize }>(
693 planar_image,
694 packed_image,
695 )
696}
697
698/// Convert YUV 422 planar format to VYUY ( YUV Packed ) format.
699///
700/// This function takes YUV 422 planar format data with 8-bit precision,
701/// and converts it to VYUY format with 8-bit per channel precision.
702/// Do not forget about odd alignment, use (width + 1) for buffers.
703///
704/// # Arguments
705///
706/// * `packed_image` - Target packed frame image.
707/// * `planar_image` - Source planar image.
708///
709/// # Panics
710///
711/// This function panics if the lengths of the planes or the input VYUY data are not valid based
712/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
713/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
714///
715pub fn yuv422_to_vyuy422(
716 packed_image: &mut YuvPackedImageMut<u8>,
717 planar_image: &YuvPlanarImage<u8>,
718) -> Result<(), YuvError> {
719 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv422 as u8 }, { Yuy2Description::VYUY as usize }>(
720 planar_image,
721 packed_image,
722 )
723}
724
725/// Convert YUV 420 planar format to VYUY ( YUV Packed ) format.
726///
727/// This function takes YUV 420 planar format data with 8-bit precision,
728/// and converts it to VYUY format with 8-bit per channel precision.
729/// Do not forget about odd alignment, use (width + 1) for buffers.
730///
731/// # Arguments
732///
733/// * `packed_image` - Target packed frame image.
734/// * `planar_image` - Source planar image.
735///
736/// # Panics
737///
738/// This function panics if the lengths of the planes or the input VYUY data are not valid based
739/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
740/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
741///
742pub fn yuv420_to_vyuy422(
743 packed_image: &mut YuvPackedImageMut<u8>,
744 planar_image: &YuvPlanarImage<u8>,
745) -> Result<(), YuvError> {
746 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv420 as u8 }, { Yuy2Description::VYUY as usize }>(
747 planar_image,
748 packed_image,
749 )
750}
751
752/// Convert YUV 444 planar format to UYVY ( YUV Packed ) format.
753///
754/// This function takes YUV 444 planar format data with 8-bit precision,
755/// and converts it to UYVY format with 8-bit per channel precision.
756/// Do not forget about odd alignment, use (width + 1) for buffers.
757///
758/// # Arguments
759///
760/// * `packed_image` - Target packed frame image.
761/// * `planar_image` - Source planar image.
762///
763/// # Panics
764///
765/// This function panics if the lengths of the planes or the input UYVY data are not valid based
766/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
767/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
768///
769pub fn yuv444_to_uyvy422(
770 packed_image: &mut YuvPackedImageMut<u8>,
771 planar_image: &YuvPlanarImage<u8>,
772) -> Result<(), YuvError> {
773 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv444 as u8 }, { Yuy2Description::UYVY as usize }>(
774 planar_image,
775 packed_image,
776 )
777}
778
779/// Convert YUV 422 planar format to UYVY ( YUV Packed ) format.
780///
781/// This function takes YUV 422 planar format data with 8-bit precision,
782/// and converts it to UYVY format with 8-bit per channel precision.
783/// Do not forget about odd alignment, use (width + 1) for buffers.
784///
785/// # Arguments
786///
787/// * `packed_image` - Target packed frame image.
788/// * `planar_image` - Source planar image.
789///
790/// # Panics
791///
792/// This function panics if the lengths of the planes or the input UYVY data are not valid based
793/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
794/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
795///
796pub fn yuv422_to_uyvy422(
797 packed_image: &mut YuvPackedImageMut<u8>,
798 planar_image: &YuvPlanarImage<u8>,
799) -> Result<(), YuvError> {
800 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv422 as u8 }, { Yuy2Description::UYVY as usize }>(
801 planar_image,
802 packed_image,
803 )
804}
805
806/// Convert YUV 420 planar format to UYVY ( YUV Packed ) format.
807///
808/// This function takes YUV 420 planar format data with 8-bit precision,
809/// and converts it to UYVY format with 8-bit per channel precision.
810/// Do not forget about odd alignment, use (width + 1) for buffers.
811///
812/// # Arguments
813///
814/// * `packed_image` - Target packed frame image.
815/// * `planar_image` - Source planar image.
816///
817/// # Panics
818///
819/// This function panics if the lengths of the planes or the input UYVY data are not valid based
820/// on the specified width, height, and strides, or if invalid YUV range or matrix is provided.
821/// Panic will be received if buffer doesn't expand with (width + 1) size for odd width
822///
823pub fn yuv420_to_uyvy422(
824 packed_image: &mut YuvPackedImageMut<u8>,
825 planar_image: &YuvPlanarImage<u8>,
826) -> Result<(), YuvError> {
827 yuv_to_yuy2_impl::<u8, { YuvChromaSubsampling::Yuv420 as u8 }, { Yuy2Description::UYVY as usize }>(
828 planar_image,
829 packed_image,
830 )
831}