31 {
32 if (source == nullptr || source->data[0] == nullptr || source->data[1] == nullptr) {
33 return false;
34 }
35 const bool p010 = source->format == AV_PIX_FMT_P010LE;
36 if (!p010 && (source->format != AV_PIX_FMT_YUV420P10LE || source->data[2] == nullptr)) {
37 return false;
38 }
39
40 width = source->width;
41 height = source->height;
42 pitch = width * 8;
43 if (width <= 0 || height <= 0) {
44 return false;
45 }
46 rgba.resize(static_cast<size_t>(width) * static_cast<size_t>(height) * 4U);
47
48 const int sampleShift = p010 ? 6 : 0;
49 const auto sample10 = [sampleShift](const uint8_t *plane, int stride, int x, int y) {
50 uint16_t raw = 0;
51 std::memcpy(&raw, plane + static_cast<size_t>(y) * stride + static_cast<size_t>(x) * 2U, sizeof(raw));
52 return static_cast<int>(raw >> sampleShift);
53 };
54
55 constexpr float CR_R = 1.4746F;
56 constexpr float CB_G = -0.16455312684366F;
57 constexpr float CR_G = -0.57135313725490F;
58 constexpr float CB_B = 1.8814F;
59 constexpr float INV_Y = 1.0F / 876.0F;
60 constexpr float INV_C = 1.0F / 896.0F;
61
62 for (int y = 0; y < height; ++y) {
63 uint16_t *destination = rgba.data() + static_cast<size_t>(y) * width * 4U;
64 const int chromaY = y >> 1;
65 for (int x = 0; x < width; ++x) {
66 const int chromaX = x >> 1;
67 const int ySample = sample10(source->data[0], source->linesize[0], x, y);
68 int cbSample = 0;
69 int crSample = 0;
70 if (p010) {
71 cbSample = sample10(source->data[1], source->linesize[1], chromaX * 2, chromaY);
72 crSample = sample10(source->data[1], source->linesize[1], chromaX * 2 + 1, chromaY);
73 } else {
74 cbSample = sample10(source->data[1], source->linesize[1], chromaX, chromaY);
75 crSample = sample10(source->data[2], source->linesize[2], chromaX, chromaY);
76 }
77
78 const float yValue = (ySample - 64) * INV_Y;
79 const float cb = (cbSample - 512) * INV_C;
80 const float cr = (crSample - 512) * INV_C;
81 const float red = std::clamp(yValue + CR_R * cr, 0.0F, 1.0F);
82 const float green = std::clamp(yValue + CB_G * cb + CR_G * cr, 0.0F, 1.0F);
83 const float blue = std::clamp(yValue + CB_B * cb, 0.0F, 1.0F);
84
85 destination[x * 4 + 0] = static_cast<uint16_t>(red * 65535.0F + 0.5F);
86 destination[x * 4 + 1] = static_cast<uint16_t>(green * 65535.0F + 0.5F);
87 destination[x * 4 + 2] = static_cast<uint16_t>(blue * 65535.0F + 0.5F);
88 destination[x * 4 + 3] = UINT16_MAX;
89 }
90 }
91
92 if (flipY) {
93 std::vector<uint16_t> row(static_cast<size_t>(width) * 4U);
94 for (int y = 0; y < height / 2; ++y) {
95 uint16_t *top = rgba.data() + static_cast<size_t>(y) * width * 4U;
96 uint16_t *bottom = rgba.data() + static_cast<size_t>(height - 1 - y) * width * 4U;
97 std::copy_n(top, row.size(), row.data());
98 std::copy_n(bottom, row.size(), top);
99 std::copy_n(row.data(), row.size(), bottom);
100 }
101 }
102 return true;
103 }