Haio
0.2.X
Homebrew Asset IO/CDN
Toggle main menu visibility
Loading...
Searching...
No Matches
yuv420.cpp
Go to the documentation of this file.
1
#include <
haio_convert.hpp
>
2
3
#include <utility>
4
5
namespace
Haio::Codecs
{
6
7
/**
8
* the way back: full range bt.601 again, and the chroma of a two by two block is the
9
* average of its four pixels rather than the top left one.
10
*
11
* taking one pixel and calling it the block would be cheaper and is what a naive
12
* encoder does; it shows up as ragged colour on edges, because the sample that
13
* happened to be first decides for three others.
14
*/
15
template
<>
16
Result<void>
Move<Color::RGBA8888, Color::YUV420>
(
Bytes
src, std::span<uint8_t> dst,
Size
size) {
17
if
(size.
width
% 2 != 0 || size.
height
% 2 != 0) {
18
HAIO_FAIL
(
InvalidInput
,
"yuv420 needs even width and height"
);
19
}
20
21
const
auto
width =
static_cast<
size_t
>
(size.
width
);
22
const
auto
height =
static_cast<
size_t
>
(size.
height
);
23
const
auto
pixels = width * height;
24
const
auto
half = width / 2;
25
const
auto
chroma = half * (height / 2);
26
27
if
(src.size() < pixels * 4 || dst.size() < pixels + chroma * 2) {
28
HAIO_FAIL
(
InvalidInput
,
"rgba8888 to yuv420 got a buffer that is too small"
);
29
}
30
31
auto
* luma = dst.data();
32
auto
* blue = luma + pixels;
33
auto
* red = blue + chroma;
34
35
const
auto
clamp = [](
int
value) {
36
return
static_cast<
uint8_t
>
(value < 0 ? 0 : value > 255 ? 255 : value);
37
};
38
39
for
(
size_t
y = 0; y < height; y++) {
40
for
(
size_t
x = 0; x < width; x++) {
41
const
auto
at = (y * width + x) * 4;
42
const
int
r = src[at + 0];
43
const
int
g = src[at + 1];
44
const
int
b = src[at + 2];
45
luma[y * width + x] = clamp((306 * r + 601 * g + 117 * b) >> 10);
46
}
47
}
48
49
for
(
size_t
y = 0; y < height; y += 2) {
50
for
(
size_t
x = 0; x < width; x += 2) {
51
int
r = 0;
52
int
g = 0;
53
int
b = 0;
54
for
(
const
auto
corner : {std::pair{y, x}, std::pair{y, x + 1},
55
std::pair{y + 1, x}, std::pair{y + 1, x + 1}}) {
56
const
auto
at = (corner.first * width + corner.second) * 4;
57
r += src[at + 0];
58
g += src[at + 1];
59
b += src[at + 2];
60
}
61
r /= 4;
62
g /= 4;
63
b /= 4;
64
65
const
auto
at = (y / 2) * half + (x / 2);
66
blue[at] = clamp(128 + ((-173 * r - 339 * g + 512 * b) >> 10));
67
red[at] = clamp(128 + ((512 * r - 429 * g - 83 * b) >> 10));
68
}
69
}
70
return
{};
71
}
72
73
template
<>
74
Result<Image<Color::YUV420>
>
Convert<Color::RGBA8888, Color::YUV420>
(
Image<Color::RGBA8888>
src) {
75
return
convertVia<Color::RGBA8888, Color::YUV420>
(std::move(src));
76
}
77
78
}
HAIO_FAIL
#define HAIO_FAIL(why, message)
Definition
haio_codec.hpp:258
haio_convert.hpp
Haio::Codecs
Definition
haio_codec.hpp:136
Haio::Codecs::Move< Color::RGBA8888, Color::YUV420 >
Result< void > Move< Color::RGBA8888, Color::YUV420 >(Bytes src, std::span< uint8_t > dst, Size size)
Definition
yuv420.cpp:16
Haio::Codecs::convertVia
Result< Image< To > > convertVia(Image< From > src)
Definition
haio_convert.hpp:21
Haio::Codecs::Convert< Color::RGBA8888, Color::YUV420 >
Result< Image< Color::YUV420 > > Convert< Color::RGBA8888, Color::YUV420 >(Image< Color::RGBA8888 > src)
Definition
yuv420.cpp:74
Haio::Result
std::expected< T, Error > Result
Definition
haio_codec.hpp:32
Haio::Size::height
int height
Definition
haio_object.hpp:14
Haio::ErrorCode::InvalidInput
@ InvalidInput
Definition
haio_codec.hpp:18
Haio::Bytes
std::span< const uint8_t > Bytes
Definition
haio_codec.hpp:14
Haio::Size::width
int width
Definition
haio_object.hpp:13
Haio::Size
Definition
haio_object.hpp:12
Haio::Image
Definition
haio_codec.hpp:36
library
backend
codecs
color
rgba8888
yuv420.cpp
Generated by
1.18.0