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}