1#![forbid(unsafe_code)]
30
31use crate::built_coefficients::get_built_forward_transform;
32use crate::sharpyuv::SharpYuvGammaTransfer;
33use crate::yuv_error::check_rgba_destination;
34use crate::yuv_support::*;
35use crate::{YuvError, YuvPlanarImageMut};
36#[cfg(feature = "rayon")]
37use rayon::iter::{IndexedParallelIterator, ParallelIterator};
38#[cfg(feature = "rayon")]
39use rayon::prelude::{ParallelSlice, ParallelSliceMut};
40
41fn sharpen_row420<const ORIGIN_CHANNELS: u8, const SAMPLING: u8, const PRECISION: i32>(
42 y: usize,
43 rgba: &[u8],
44 y_plane: &mut [u8],
45 u_plane: &mut [u8],
46 v_plane: &mut [u8],
47 rgb_layout: &[u16],
48 rgb_layout_next_lane: &[u16],
49 gamma_map_table: &[u8; u16::MAX as usize + 1],
50 range: &YuvChromaRange,
51 transform: &CbCrForwardTransform<i32>,
52 width: usize,
53) {
54 let src_chans: YuvSourceChannels = ORIGIN_CHANNELS.into();
55 let channels = src_chans.get_channels_count();
56
57 let rounding_const_bias: i32 = (1 << (PRECISION - 1)) - 1;
58 let bias_y = range.bias_y as i32 * (1 << PRECISION) + rounding_const_bias;
59 let bias_uv = range.bias_uv as i32 * (1 << PRECISION) + rounding_const_bias;
60
61 let i_bias_y = range.bias_y as i32;
62 let i_cap_y = range.range_y as i32 + i_bias_y;
63 let i_cap_uv = i_bias_y + range.range_uv as i32;
64
65 let y_even_row = y & 1 == 0;
66
67 for (((((y_dst, u_dst), v_dst), rgba), rgb_linearized), rgb_linearized_next) in y_plane
68 .chunks_exact_mut(2)
69 .zip(u_plane.iter_mut())
70 .zip(v_plane.iter_mut())
71 .zip(rgba.chunks_exact(channels * 2))
72 .zip(rgb_layout.chunks_exact(2 * 3))
73 .zip(rgb_layout_next_lane.chunks_exact(2 * 3))
74 {
75 let r0 = rgba[src_chans.get_r_channel_offset()] as i32;
76 let g0 = rgba[src_chans.get_g_channel_offset()] as i32;
77 let b0 = rgba[src_chans.get_b_channel_offset()] as i32;
78
79 let y_0 = (r0 * transform.yr + g0 * transform.yg + b0 * transform.yb + bias_y) >> PRECISION;
80 y_dst[0] = y_0.min(i_cap_y) as u8;
81
82 let rgba_2 = &rgba[channels..channels * 2];
83
84 let r1 = rgba_2[src_chans.get_r_channel_offset()] as i32;
85 let g1 = rgba_2[src_chans.get_g_channel_offset()] as i32;
86 let b1 = rgba_2[src_chans.get_b_channel_offset()] as i32;
87
88 let y_1 = (r1 * transform.yr + g1 * transform.yg + b1 * transform.yb + bias_y) >> PRECISION;
89 y_dst[1] = y_1.min(i_cap_y) as u8;
90
91 if y_even_row {
92 let sharp_r_c = rgb_linearized[src_chans.get_r_channel_offset()];
93 let sharp_g_c = rgb_linearized[src_chans.get_g_channel_offset()];
94 let sharp_b_c = rgb_linearized[src_chans.get_b_channel_offset()];
95
96 let rgb_linearized_2 = &rgb_linearized[3..(3 + 3)];
97
98 let sharp_r_next = rgb_linearized_2[src_chans.get_r_channel_offset()];
99 let sharp_g_next = rgb_linearized_2[src_chans.get_g_channel_offset()];
100 let sharp_b_next = rgb_linearized_2[src_chans.get_b_channel_offset()];
101
102 let sharp_r_c_next_row = rgb_linearized_next[src_chans.get_r_channel_offset()];
103 let sharp_g_c_next_row = rgb_linearized_next[src_chans.get_g_channel_offset()];
104 let sharp_b_c_next_row = rgb_linearized_next[src_chans.get_b_channel_offset()];
105
106 let rgb_linearized_next_2 = &rgb_linearized_next[3..(3 + 3)];
107
108 let sharp_r_next_row = rgb_linearized_next_2[src_chans.get_r_channel_offset()];
109 let sharp_g_next_row = rgb_linearized_next_2[src_chans.get_g_channel_offset()];
110 let sharp_b_next_row = rgb_linearized_next_2[src_chans.get_b_channel_offset()];
111
112 const ROUNDING_SHARP: i32 = 1 << 3;
113
114 let interpolated_r = ((sharp_r_c as i32 * 9
115 + sharp_r_next as i32 * 3
116 + sharp_r_c_next_row as i32 * 3
117 + sharp_r_next_row as i32
118 + ROUNDING_SHARP)
119 >> 4) as u16;
120 let interpolated_g = ((sharp_g_c as i32 * 9
121 + sharp_g_next as i32 * 3
122 + sharp_g_c_next_row as i32 * 3
123 + sharp_g_next_row as i32
124 + ROUNDING_SHARP)
125 >> 4) as u16;
126 let interpolated_b = ((sharp_b_c as i32 * 9
127 + sharp_b_next as i32 * 3
128 + sharp_b_c_next_row as i32 * 3
129 + sharp_b_next_row as i32
130 + ROUNDING_SHARP)
131 >> 4) as u16;
132
133 let corrected_r = gamma_map_table[interpolated_r as usize] as i32;
134 let corrected_g = gamma_map_table[interpolated_g as usize] as i32;
135 let corrected_b = gamma_map_table[interpolated_b as usize] as i32;
136
137 let cb = (corrected_r * transform.cb_r
138 + corrected_g * transform.cb_g
139 + corrected_b * transform.cb_b
140 + bias_uv)
141 >> PRECISION;
142 let cr = (corrected_r * transform.cr_r
143 + corrected_g * transform.cr_g
144 + corrected_b * transform.cr_b
145 + bias_uv)
146 >> PRECISION;
147 *u_dst = cb.max(i_bias_y).min(i_cap_uv) as u8;
148 *v_dst = cr.max(i_bias_y).min(i_cap_uv) as u8;
149 }
150 }
151
152 let rem_rgba = rgba.chunks_exact(channels * 2).remainder();
153
154 if width & 1 != 0 && !rem_rgba.is_empty() {
155 let rgba = &rem_rgba[0..3];
156 let y_last = y_plane.last_mut().unwrap();
157 let r0 = rgba[src_chans.get_r_channel_offset()] as i32;
158 let g0 = rgba[src_chans.get_g_channel_offset()] as i32;
159 let b0 = rgba[src_chans.get_b_channel_offset()] as i32;
160
161 let y_1 = (r0 * transform.yr + g0 * transform.yg + b0 * transform.yb + bias_y) >> PRECISION;
162 *y_last = y_1.min(i_cap_y) as u8;
163
164 if y_even_row {
165 let rgba_lin = rgb_layout.chunks_exact(3).last().unwrap();
166 let rgba_lin = &rgba_lin[0..3];
167 let sharp_r_c = rgba_lin[src_chans.get_r_channel_offset()];
168 let sharp_g_c = rgba_lin[src_chans.get_g_channel_offset()];
169 let sharp_b_c = rgba_lin[src_chans.get_b_channel_offset()];
170
171 let rgba_lin_next = rgb_layout_next_lane.chunks_exact(3).last().unwrap();
172 let rgba_lin_next = &rgba_lin_next[0..3];
173 let sharp_r_c_next = rgba_lin_next[src_chans.get_r_channel_offset()];
174 let sharp_g_c_next = rgba_lin_next[src_chans.get_g_channel_offset()];
175 let sharp_b_c_next = rgba_lin_next[src_chans.get_b_channel_offset()];
176
177 const ROUNDING_SHARP: i32 = 1 << 3;
178
179 let interpolated_r =
180 ((sharp_r_c as i32 * 12 + sharp_r_c_next as i32 * 4 + ROUNDING_SHARP) >> 4) as u16;
181 let interpolated_g =
182 ((sharp_g_c as i32 * 12 + sharp_g_c_next as i32 * 4 + ROUNDING_SHARP) >> 4) as u16;
183 let interpolated_b =
184 ((sharp_b_c as i32 * 12 + sharp_b_c_next as i32 * 4 + ROUNDING_SHARP) >> 4) as u16;
185
186 let corrected_r = gamma_map_table[interpolated_r as usize] as i32;
187 let corrected_g = gamma_map_table[interpolated_g as usize] as i32;
188 let corrected_b = gamma_map_table[interpolated_b as usize] as i32;
189
190 let cb = (corrected_r * transform.cb_r
191 + corrected_g * transform.cb_g
192 + corrected_b * transform.cb_b
193 + bias_uv)
194 >> PRECISION;
195 let cr = (corrected_r * transform.cr_r
196 + corrected_g * transform.cr_g
197 + corrected_b * transform.cr_b
198 + bias_uv)
199 >> PRECISION;
200 let u_last = u_plane.last_mut().unwrap();
201 let v_last = v_plane.last_mut().unwrap();
202 *u_last = cb.max(i_bias_y).min(i_cap_uv) as u8;
203 *v_last = cr.max(i_bias_y).min(i_cap_uv) as u8;
204 }
205 }
206}
207
208fn sharpen_row422<const ORIGIN_CHANNELS: u8, const SAMPLING: u8, const PRECISION: i32>(
209 rgba: &[u8],
210 y_plane: &mut [u8],
211 u_plane: &mut [u8],
212 v_plane: &mut [u8],
213 rgb_layout: &[u16],
214 gamma_map_table: &[u8; u16::MAX as usize + 1],
215 range: &YuvChromaRange,
216 transform: &CbCrForwardTransform<i32>,
217 width: usize,
218) {
219 let src_chans: YuvSourceChannels = ORIGIN_CHANNELS.into();
220 let channels = src_chans.get_channels_count();
221
222 let rounding_const_bias: i32 = (1 << (PRECISION - 1)) - 1;
223 let bias_y = range.bias_y as i32 * (1 << PRECISION) + rounding_const_bias;
224 let bias_uv = range.bias_uv as i32 * (1 << PRECISION) + rounding_const_bias;
225
226 let i_bias_y = range.bias_y as i32;
227 let i_cap_y = range.range_y as i32 + i_bias_y;
228 let i_cap_uv = i_bias_y + range.range_uv as i32;
229
230 for ((((y_dst, u_dst), v_dst), rgba), rgb_linearized) in y_plane
231 .chunks_exact_mut(2)
232 .zip(u_plane.iter_mut())
233 .zip(v_plane.iter_mut())
234 .zip(rgba.chunks_exact(channels * 2))
235 .zip(rgb_layout.chunks_exact(2 * 3))
236 {
237 let r0 = rgba[src_chans.get_r_channel_offset()] as i32;
238 let g0 = rgba[src_chans.get_g_channel_offset()] as i32;
239 let b0 = rgba[src_chans.get_b_channel_offset()] as i32;
240
241 let sharp_r_c = rgb_linearized[src_chans.get_r_channel_offset()];
242 let sharp_g_c = rgb_linearized[src_chans.get_g_channel_offset()];
243 let sharp_b_c = rgb_linearized[src_chans.get_b_channel_offset()];
244
245 let y_0 = (r0 * transform.yr + g0 * transform.yg + b0 * transform.yb + bias_y) >> PRECISION;
246 y_dst[0] = y_0.min(i_cap_y) as u8;
247
248 let rgba_2 = &rgba[channels..channels * 2];
249
250 let r1 = rgba_2[src_chans.get_r_channel_offset()] as i32;
251 let g1 = rgba_2[src_chans.get_g_channel_offset()] as i32;
252 let b1 = rgba_2[src_chans.get_b_channel_offset()] as i32;
253
254 let y_1 = (r1 * transform.yr + g1 * transform.yg + b1 * transform.yb + bias_y) >> PRECISION;
255 y_dst[1] = y_1.min(i_cap_y) as u8;
256
257 let rgb_linearized_2 = &rgb_linearized[3..(3 + 3)];
258
259 let sharp_r_next = rgb_linearized_2[src_chans.get_r_channel_offset()];
260 let sharp_g_next = rgb_linearized_2[src_chans.get_g_channel_offset()];
261 let sharp_b_next = rgb_linearized_2[src_chans.get_b_channel_offset()];
262
263 const ROUNDING_SHARP: i32 = 1 << 3;
264
265 let interpolated_r =
266 ((sharp_r_c as i32 * 12 + sharp_r_next as i32 * 4 + ROUNDING_SHARP) >> 4) as u16;
267 let interpolated_g =
268 ((sharp_g_c as i32 * 12 + sharp_g_next as i32 * 4 + ROUNDING_SHARP) >> 4) as u16;
269 let interpolated_b =
270 ((sharp_b_c as i32 * 12 + sharp_b_next as i32 * 4 + ROUNDING_SHARP) >> 4) as u16;
271
272 let corrected_r = gamma_map_table[interpolated_r as usize] as i32;
273 let corrected_g = gamma_map_table[interpolated_g as usize] as i32;
274 let corrected_b = gamma_map_table[interpolated_b as usize] as i32;
275
276 let cb = (corrected_r * transform.cb_r
277 + corrected_g * transform.cb_g
278 + corrected_b * transform.cb_b
279 + bias_uv)
280 >> PRECISION;
281 let cr = (corrected_r * transform.cr_r
282 + corrected_g * transform.cr_g
283 + corrected_b * transform.cr_b
284 + bias_uv)
285 >> PRECISION;
286 *u_dst = cb.max(i_bias_y).min(i_cap_uv) as u8;
287 *v_dst = cr.max(i_bias_y).min(i_cap_uv) as u8;
288 }
289
290 let rem_rgba = rgba.chunks_exact(channels * 2).remainder();
291
292 if width & 1 != 0 && !rem_rgba.is_empty() {
293 let rgba = &rem_rgba[0..3];
294 let y_last = y_plane.last_mut().unwrap();
295 let r0 = rgba[src_chans.get_r_channel_offset()] as i32;
296 let g0 = rgba[src_chans.get_g_channel_offset()] as i32;
297 let b0 = rgba[src_chans.get_b_channel_offset()] as i32;
298
299 let y_1 = (r0 * transform.yr + g0 * transform.yg + b0 * transform.yb + bias_y) >> PRECISION;
300 *y_last = y_1.min(i_cap_y) as u8;
301
302 let cb = (r0 * transform.cb_r + g0 * transform.cb_g + b0 * transform.cb_b + bias_uv)
303 >> PRECISION;
304 let cr = (r0 * transform.cr_r + g0 * transform.cr_g + b0 * transform.cr_b + bias_uv)
305 >> PRECISION;
306
307 let u_last = u_plane.last_mut().unwrap();
308 let v_last = v_plane.last_mut().unwrap();
309 *u_last = cb.max(i_bias_y).min(i_cap_uv) as u8;
310 *v_last = cr.max(i_bias_y).min(i_cap_uv) as u8;
311 }
312}
313
314fn rgbx_to_sharp_yuv<const ORIGIN_CHANNELS: u8, const SAMPLING: u8>(
315 planar_image: &mut YuvPlanarImageMut<u8>,
316 rgba: &[u8],
317 rgba_stride: u32,
318 range: YuvRange,
319 matrix: YuvStandardMatrix,
320 sharp_yuv_gamma_transfer: SharpYuvGammaTransfer,
321) -> Result<(), YuvError> {
322 let chroma_subsampling: YuvChromaSubsampling = SAMPLING.into();
323 let src_chans: YuvSourceChannels = ORIGIN_CHANNELS.into();
324
325 check_rgba_destination(
326 rgba,
327 rgba_stride,
328 planar_image.width,
329 planar_image.height,
330 src_chans.get_channels_count(),
331 )?;
332 planar_image.check_constraints(chroma_subsampling)?;
333
334 let mut linear_map_table = [0u16; 256];
335 let mut gamma_map_table = [0u8; u16::MAX as usize + 1];
336
337 let linear_scale = (1. / 255.) as f32;
338 let gamma_scale = 1. / u16::MAX as f32;
339
340 for (i, item) in linear_map_table.iter_mut().enumerate() {
341 let linear = sharp_yuv_gamma_transfer.linearize(i as f32 * linear_scale);
342 *item = (linear * u16::MAX as f32) as u16;
343 }
344
345 for (i, item) in gamma_map_table.iter_mut().enumerate() {
346 let gamma = sharp_yuv_gamma_transfer.gamma(i as f32 * gamma_scale);
347 *item = (gamma * 255.) as u8;
348 }
349
350 let mut rgb_layout: Vec<u16> =
352 vec![0u16; planar_image.width as usize * planar_image.height as usize * 3];
353
354 let rgb_layout_stride_len = planar_image.width as usize * 3;
355
356 let iter_linearize;
357 #[cfg(not(feature = "rayon"))]
358 {
359 iter_linearize = rgb_layout
360 .chunks_exact_mut(rgb_layout_stride_len)
361 .zip(rgba.chunks_exact(rgba_stride as usize));
362 }
363 #[cfg(feature = "rayon")]
364 {
365 iter_linearize = rgb_layout
366 .par_chunks_exact_mut(rgb_layout_stride_len)
367 .zip(rgba.par_chunks_exact(rgba_stride as usize));
368 }
369
370 iter_linearize.for_each(|(rgb_layout_cast, src_layout)| {
371 for (dst, src) in rgb_layout_cast
372 .chunks_exact_mut(3)
373 .zip(src_layout.chunks_exact(src_chans.get_channels_count()))
374 {
375 dst[0] = linear_map_table[src[0] as usize];
376 dst[1] = linear_map_table[src[1] as usize];
377 dst[2] = linear_map_table[src[2] as usize];
378 }
379 });
380
381 let chroma_range = get_yuv_range(8, range);
382 let kr_kb = matrix.get_kr_kb();
383 let max_range_p8 = (1u32 << 8u32) - 1u32;
384 const PRECISION: i32 = 13;
385 let transform =
386 if let Some(stored_t) = get_built_forward_transform(PRECISION as u32, 8, range, matrix) {
387 stored_t
388 } else {
389 let transform_precise = get_forward_transform(
390 max_range_p8,
391 chroma_range.range_y,
392 chroma_range.range_uv,
393 kr_kb.kr,
394 kr_kb.kb,
395 );
396 transform_precise.to_integers(PRECISION as u32)
397 };
398
399 let y_iter;
400 let u_iter;
401 let v_iter;
402 let rgb_iter;
403
404 if chroma_subsampling == YuvChromaSubsampling::Yuv420 {
405 #[cfg(feature = "rayon")]
406 {
407 y_iter = planar_image
408 .y_plane
409 .borrow_mut()
410 .par_chunks_exact_mut(planar_image.y_stride as usize * 2);
411 u_iter = planar_image
412 .u_plane
413 .borrow_mut()
414 .par_chunks_exact_mut(planar_image.u_stride as usize);
415 v_iter = planar_image
416 .v_plane
417 .borrow_mut()
418 .par_chunks_exact_mut(planar_image.v_stride as usize);
419 rgb_iter = rgba.par_chunks_exact(rgba_stride as usize * 2);
420 }
421 #[cfg(not(feature = "rayon"))]
422 {
423 y_iter = planar_image
424 .y_plane
425 .borrow_mut()
426 .chunks_exact_mut(planar_image.y_stride as usize * 2);
427 u_iter = planar_image
428 .u_plane
429 .borrow_mut()
430 .chunks_exact_mut(planar_image.u_stride as usize);
431 v_iter = planar_image
432 .v_plane
433 .borrow_mut()
434 .chunks_exact_mut(planar_image.v_stride as usize);
435 rgb_iter = rgba.chunks_exact(rgba_stride as usize * 2);
436 }
437 } else {
438 #[cfg(feature = "rayon")]
439 {
440 y_iter = planar_image
441 .y_plane
442 .borrow_mut()
443 .par_chunks_exact_mut(planar_image.y_stride as usize);
444 u_iter = planar_image
445 .u_plane
446 .borrow_mut()
447 .par_chunks_exact_mut(planar_image.u_stride as usize);
448 v_iter = planar_image
449 .v_plane
450 .borrow_mut()
451 .par_chunks_exact_mut(planar_image.v_stride as usize);
452 rgb_iter = rgba.par_chunks_exact(rgba_stride as usize);
453 }
454 #[cfg(not(feature = "rayon"))]
455 {
456 y_iter = planar_image
457 .y_plane
458 .borrow_mut()
459 .chunks_exact_mut(planar_image.y_stride as usize);
460 u_iter = planar_image
461 .u_plane
462 .borrow_mut()
463 .chunks_exact_mut(planar_image.u_stride as usize);
464 v_iter = planar_image
465 .v_plane
466 .borrow_mut()
467 .chunks_exact_mut(planar_image.v_stride as usize);
468 rgb_iter = rgba.chunks_exact(rgba_stride as usize);
469 }
470 }
471
472 let full_iter = rgb_iter.zip(y_iter).zip(u_iter).zip(v_iter);
473
474 full_iter
475 .enumerate()
476 .for_each(|(j, (((rgba, y_plane), u_plane), v_plane))| {
477 if chroma_subsampling == YuvChromaSubsampling::Yuv420 {
478 let v_y = j * 2;
479
480 for (virtual_y, (y_plane, rgba)) in y_plane
481 .chunks_exact_mut(planar_image.y_stride as usize)
482 .zip(rgba.chunks_exact(rgba_stride as usize))
483 .enumerate()
484 {
485 let y = virtual_y + v_y;
486 let rgb_layout_start = y * rgb_layout_stride_len;
487 let rgb_layout_start_next = (y + 1) * rgb_layout_stride_len;
488 let rgb_layout_lane = &rgb_layout
489 [rgb_layout_start..((planar_image.width as usize) * 3 + rgb_layout_start)];
490 let rgb_layout_next_lane = if y + 1 < planar_image.height as usize {
491 &rgb_layout[rgb_layout_start_next
492 ..((planar_image.width as usize) * 3 + rgb_layout_start_next)]
493 } else {
494 rgb_layout_lane
495 };
496 sharpen_row420::<ORIGIN_CHANNELS, SAMPLING, PRECISION>(
497 y,
498 &rgba[0..planar_image.width as usize * src_chans.get_channels_count()],
499 &mut y_plane[0..planar_image.width as usize],
500 &mut u_plane[0..(planar_image.width as usize).div_ceil(2)],
501 &mut v_plane[0..(planar_image.width as usize).div_ceil(2)],
502 rgb_layout_lane,
503 rgb_layout_next_lane,
504 &gamma_map_table,
505 &chroma_range,
506 &transform,
507 planar_image.width as usize,
508 );
509 }
510 } else {
511 let y = j;
512 let rgb_layout_start = y * rgb_layout_stride_len;
513 let rgb_layout_lane = &rgb_layout
514 [rgb_layout_start..((planar_image.width as usize) * 3 + rgb_layout_start)];
515 sharpen_row422::<ORIGIN_CHANNELS, SAMPLING, PRECISION>(
516 &rgba[0..planar_image.width as usize * src_chans.get_channels_count()],
517 &mut y_plane[0..planar_image.width as usize],
518 &mut u_plane[0..(planar_image.width as usize).div_ceil(2)],
519 &mut v_plane[0..(planar_image.width as usize).div_ceil(2)],
520 rgb_layout_lane,
521 &gamma_map_table,
522 &chroma_range,
523 &transform,
524 planar_image.width as usize,
525 );
526 }
527 });
528
529 if planar_image.height & 1 != 0 && chroma_subsampling == YuvChromaSubsampling::Yuv420 {
531 let y_iter = planar_image
532 .y_plane
533 .borrow_mut()
534 .chunks_exact_mut(planar_image.y_stride as usize)
535 .rev()
536 .take(1);
537 let u_iter = planar_image
538 .u_plane
539 .borrow_mut()
540 .chunks_exact_mut(planar_image.u_stride as usize)
541 .rev()
542 .take(1);
543 let v_iter = planar_image
544 .v_plane
545 .borrow_mut()
546 .chunks_exact_mut(planar_image.v_stride as usize)
547 .rev()
548 .take(1);
549 let rgb_iter = rgba.chunks_exact(rgba_stride as usize).rev().take(1);
550 let rgb_linearized_iter = rgb_layout
551 .chunks_exact_mut(rgb_layout_stride_len)
552 .rev()
553 .take(1);
554
555 let full_iter = rgb_iter
556 .zip(rgb_linearized_iter)
557 .zip(y_iter)
558 .zip(u_iter)
559 .zip(v_iter);
560
561 full_iter.for_each(|((((rgba, rgb_layout), y_plane), u_plane), v_plane)| {
562 let y = planar_image.height as usize - 1;
563 let rgb_layout_lane: &[u16] = rgb_layout;
564 let rgb_layout_next_lane: &[u16] = rgb_layout;
565 sharpen_row420::<ORIGIN_CHANNELS, SAMPLING, PRECISION>(
566 y,
567 &rgba[0..planar_image.width as usize * src_chans.get_channels_count()],
568 &mut y_plane[0..planar_image.width as usize],
569 &mut u_plane[0..(planar_image.width as usize).div_ceil(2)],
570 &mut v_plane[0..(planar_image.width as usize).div_ceil(2)],
571 rgb_layout_lane,
572 rgb_layout_next_lane,
573 &gamma_map_table,
574 &chroma_range,
575 &transform,
576 planar_image.width as usize,
577 );
578 });
579 }
580
581 Ok(())
582}
583
584pub fn rgb_to_sharp_yuv422(
603 planar_image: &mut YuvPlanarImageMut<u8>,
604 rgb: &[u8],
605 rgb_stride: u32,
606 range: YuvRange,
607 matrix: YuvStandardMatrix,
608 gamma_transfer: SharpYuvGammaTransfer,
609) -> Result<(), YuvError> {
610 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Rgb as u8 }, { YuvChromaSubsampling::Yuv422 as u8 }>(
611 planar_image,
612 rgb,
613 rgb_stride,
614 range,
615 matrix,
616 gamma_transfer,
617 )
618}
619
620pub fn bgr_to_sharp_yuv422(
639 planar_image: &mut YuvPlanarImageMut<u8>,
640 bgr: &[u8],
641 bgr_stride: u32,
642 range: YuvRange,
643 matrix: YuvStandardMatrix,
644 gamma_transfer: SharpYuvGammaTransfer,
645) -> Result<(), YuvError> {
646 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Bgr as u8 }, { YuvChromaSubsampling::Yuv422 as u8 }>(
647 planar_image,
648 bgr,
649 bgr_stride,
650 range,
651 matrix,
652 gamma_transfer,
653 )
654}
655
656pub fn rgba_to_sharp_yuv422(
675 planar_image: &mut YuvPlanarImageMut<u8>,
676 rgba: &[u8],
677 rgba_stride: u32,
678 range: YuvRange,
679 matrix: YuvStandardMatrix,
680 gamma_transfer: SharpYuvGammaTransfer,
681) -> Result<(), YuvError> {
682 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Rgba as u8 }, { YuvChromaSubsampling::Yuv422 as u8 }>(
683 planar_image,
684 rgba,
685 rgba_stride,
686 range,
687 matrix,
688 gamma_transfer,
689 )
690}
691
692pub fn bgra_to_sharp_yuv422(
711 planar_image: &mut YuvPlanarImageMut<u8>,
712 bgra: &[u8],
713 bgra_stride: u32,
714 range: YuvRange,
715 matrix: YuvStandardMatrix,
716 gamma_transfer: SharpYuvGammaTransfer,
717) -> Result<(), YuvError> {
718 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Bgra as u8 }, { YuvChromaSubsampling::Yuv422 as u8 }>(
719 planar_image,
720 bgra,
721 bgra_stride,
722 range,
723 matrix,
724 gamma_transfer,
725 )
726}
727
728pub fn rgb_to_sharp_yuv420(
754 planar_image: &mut YuvPlanarImageMut<u8>,
755 rgb: &[u8],
756 rgb_stride: u32,
757 range: YuvRange,
758 matrix: YuvStandardMatrix,
759 gamma_transfer: SharpYuvGammaTransfer,
760) -> Result<(), YuvError> {
761 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Rgb as u8 }, { YuvChromaSubsampling::Yuv420 as u8 }>(
762 planar_image,
763 rgb,
764 rgb_stride,
765 range,
766 matrix,
767 gamma_transfer,
768 )
769}
770
771pub fn bgr_to_sharp_yuv420(
790 planar_image: &mut YuvPlanarImageMut<u8>,
791 bgr: &[u8],
792 bgr_stride: u32,
793 range: YuvRange,
794 matrix: YuvStandardMatrix,
795 gamma_transfer: SharpYuvGammaTransfer,
796) -> Result<(), YuvError> {
797 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Bgr as u8 }, { YuvChromaSubsampling::Yuv420 as u8 }>(
798 planar_image,
799 bgr,
800 bgr_stride,
801 range,
802 matrix,
803 gamma_transfer,
804 )
805}
806
807pub fn rgba_to_sharp_yuv420(
826 planar_image: &mut YuvPlanarImageMut<u8>,
827 rgba: &[u8],
828 rgba_stride: u32,
829 range: YuvRange,
830 matrix: YuvStandardMatrix,
831 gamma_transfer: SharpYuvGammaTransfer,
832) -> Result<(), YuvError> {
833 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Rgba as u8 }, { YuvChromaSubsampling::Yuv420 as u8 }>(
834 planar_image,
835 rgba,
836 rgba_stride,
837 range,
838 matrix,
839 gamma_transfer,
840 )
841}
842
843pub fn bgra_to_sharp_yuv420(
862 planar_image: &mut YuvPlanarImageMut<u8>,
863 bgra: &[u8],
864 bgra_stride: u32,
865 range: YuvRange,
866 matrix: YuvStandardMatrix,
867 gamma_transfer: SharpYuvGammaTransfer,
868) -> Result<(), YuvError> {
869 rgbx_to_sharp_yuv::<{ YuvSourceChannels::Bgra as u8 }, { YuvChromaSubsampling::Yuv420 as u8 }>(
870 planar_image,
871 bgra,
872 bgra_stride,
873 range,
874 matrix,
875 gamma_transfer,
876 )
877}