1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
pub fn convert_rgb_to_yuv420(img: &[u8], width: u32, height: u32, bytes_per_pixel: usize) -> Vec<u8> {
let frame_size: usize = (width * height) as usize;
let chroma_size: usize = frame_size / 4;
let mut y_index: usize = 0;
let mut u_index = frame_size;
let mut v_index = frame_size + chroma_size;
let mut yuv = vec![0; (width * height * 3 / 2) as usize];
let mut r: u16;
let mut g: u16;
let mut b: u16;
let mut y: u16;
let mut u: i16;
let mut v: i16;
let mut index: usize = 0;
for j in 0..height {
for _ in 0..width {
r = img[index * bytes_per_pixel] as u16;
g = img[index * bytes_per_pixel + 1] as u16;
b = img[index * bytes_per_pixel + 2] as u16;
index += 1;
y = (77 * r + 150 * g + 29 * b + 128) >> 8;
u = ((-43 * r as i16 - 84 * g as i16 + 127 * b as i16 + 128) >> 8) + 128;
v = ((127 * r as i16 - 106 * g as i16 - 21 * b as i16 + 128) >> 8) + 128;
yuv[y_index] = clamp(y as i32);
y_index += 1;
if j % 2 == 0 && index % 2 == 0 {
yuv[u_index] = clamp(u as i32);
u_index += 1;
yuv[v_index] = clamp(v as i32);
v_index += 1;
}
}
}
yuv
}
fn clamp(val: i32) -> u8 {
match val {
ref v if v < &0 => 0,
ref v if v > &255 => 255,
v => v as u8,
}
}
#[cfg(test)]
mod tests {
#[test]
fn rgb_to_yuv() {
use super::convert_rgb_to_yuv420;
let rgb = vec![0u8; 12];
let expected = vec![0u8, 0u8, 0u8, 0u8, 128u8, 128u8];
let yuv = convert_rgb_to_yuv420(&rgb, 2, 2, 3);
assert_eq!(yuv.len(), rgb.len() / 2);
for (val, exp) in yuv.iter().zip(expected.iter()) {
assert_eq!(val, exp);
}
}
#[test]
fn rgba_to_yuv_from_file() {
extern crate png;
use std::fs::File;
use super::convert_rgb_to_yuv420;
let decoder = png::Decoder::new(File::open("pic/ferris.png").unwrap());
let (info, mut reader) = decoder.read_info().unwrap();
let mut buf = vec![0; info.buffer_size()];
reader.next_frame(&mut buf).unwrap();
let yuv = convert_rgb_to_yuv420(&buf, info.width, info.height, info.line_size / info.width as usize);
assert_eq!(yuv.len(), buf.len() / 4 * 3 / 2);
}
}