Skip to content

Commit 3c04762

Browse files
committed
vdec/openapv: add convs to R10k and R12L
again ported to from_planar from from_lavc OpenAPV compression implements conversion from R10k and R12L but the video decompression actually didn't. Provided that the use-case for those pixfmts is DeckLink (without fake Y416 conversion), it doesn't make much sense because we won't get the 4:4:4 output back on the display. So added conversions to R10k and R12L for the symmetry. Added also to RGB and RGBA (just for 10 bit 4:4:4) - there is perhaps just a little use for that but the vcomp/oapv implements the reverse.
1 parent 1dd3cc2 commit 3c04762

4 files changed

Lines changed: 262 additions & 238 deletions

File tree

‎src/from_planar.c‎

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <stdint.h> // for uint32_t, uintptr_t, uint16_t, uint64_t
4848
#include <string.h> // for memcpy
4949

50+
#include "color_space.h"
5051
#include "compat/c23.h" // for size_t, NULL, countof, nullptr, ptrdiff_t
5152
#include "types.h" // for depth
5253
#include "utils/macros.h" // for OPTIMIZED_FOR
@@ -897,3 +898,225 @@ yuv444p16le_to_v210(struct from_planar_data d)
897898
yuv444p1Xle_to_v210(d, DEPTH16);
898899
}
899900

901+
#if defined __GNUC__
902+
// actually faster with -02 with GCC
903+
#if !defined __clang__
904+
#pragma GCC push_options
905+
#pragma GCC optimize("O2")
906+
#endif
907+
#endif
908+
[[gnu::always_inline]] static inline void
909+
yuv444pXXle_to_r12l(struct from_planar_data d, int depth)
910+
{
911+
const int width = d.width;
912+
const size_t height = d.height;
913+
914+
assert((uintptr_t) d.in_linesize[0] % 2 == 0);
915+
assert((uintptr_t) d.in_linesize[1] % 2 == 0);
916+
assert((uintptr_t) d.in_linesize[2] % 2 == 0);
917+
918+
int lmt_rng = d.in_ycbcr_full_rng ? 0 : depth;
919+
const struct color_coeffs cfs = *get_color_coeffs(d.cs_coeffs, lmt_rng);
920+
for (size_t y = 0; y < height; ++y) {
921+
const uint16_t *src_y = (const void *) (d.in_data[0] + (d.in_linesize[0] * y));
922+
const uint16_t *src_cb = (const void *) (d.in_data[1] + (d.in_linesize[1] * y));
923+
const uint16_t *src_cr = (const void *) (d.in_data[2] + (d.in_linesize[2] * y));
924+
unsigned char *dst = d.out_data + (y * d.out_pitch);
925+
926+
for (int x = 0; x < width; x += 8) {
927+
comp_type_t r[8];
928+
comp_type_t g[8];
929+
comp_type_t b[8];
930+
OPTIMIZED_FOR (int j = 0; j < 8; ++j) {
931+
comp_type_t y = (cfs.y_scale * (*src_y++ - (1<<(depth-4))));
932+
comp_type_t cr = *src_cr++ - (1<<(depth-1));
933+
comp_type_t cb = *src_cb++ - (1<<(depth-1));
934+
comp_type_t rr = YCBCR_TO_R(cfs, y, cb, cr) >> (COMP_BASE-12+depth);
935+
comp_type_t gg = YCBCR_TO_G(cfs, y, cb, cr) >> (COMP_BASE-12+depth);
936+
comp_type_t bb = YCBCR_TO_B(cfs, y, cb, cr) >> (COMP_BASE-12+depth);
937+
r[j] = CLAMP_FULL(rr, 12);
938+
g[j] = CLAMP_FULL(gg, 12);
939+
b[j] = CLAMP_FULL(bb, 12);
940+
}
941+
942+
dst[0] = r[0] & 0xff;
943+
dst[1] = (g[0] & 0xf) << 4 | r[0] >> 8;
944+
dst[2] = g[0] >> 4;
945+
dst[3] = b[0] & 0xff;
946+
dst[4 + 0] = (r[1] & 0xf) << 4 | b[0] >> 8;
947+
dst[4 + 1] = r[1] >> 4;
948+
dst[4 + 2] = g[1] & 0xff;
949+
dst[4 + 3] = (b[1] & 0xf) << 4 | g[1] >> 8;
950+
dst[8 + 0] = b[1] >> 4;
951+
dst[8 + 1] = r[2] & 0xff;
952+
dst[8 + 2] = (g[2] & 0xf) << 4 | r[2] >> 8;
953+
dst[8 + 3] = g[2] >> 4;
954+
dst[12 + 0] = b[2] & 0xff;
955+
dst[12 + 1] = (r[3] & 0xf) << 4 | b[2] >> 8;
956+
dst[12 + 2] = r[3] >> 4;
957+
dst[12 + 3] = g[3] & 0xff;
958+
dst[16 + 0] = (b[3] & 0xf) << 4 | g[3] >> 8;
959+
dst[16 + 1] = b[3] >> 4;
960+
dst[16 + 2] = r[4] & 0xff;
961+
dst[16 + 3] = (g[4] & 0xf) << 4 | r[4] >> 8;
962+
dst[20 + 0] = g[4] >> 4;
963+
dst[20 + 1] = b[4] & 0xff;
964+
dst[20 + 2] = (r[5] & 0xf) << 4 | b[4] >> 8;
965+
dst[20 + 3] = r[5] >> 4;;
966+
dst[24 + 0] = g[5] & 0xff;
967+
dst[24 + 1] = (b[5] & 0xf) << 4 | g[5] >> 8;
968+
dst[24 + 2] = b[5] >> 4;
969+
dst[24 + 3] = r[6] & 0xff;
970+
dst[28 + 0] = (g[6] & 0xf) << 4 | r[6] >> 8;
971+
dst[28 + 1] = g[6] >> 4;
972+
dst[28 + 2] = b[6] & 0xff;
973+
dst[28 + 3] = (r[7] & 0xf) << 4 | b[6] >> 8;
974+
dst[32 + 0] = r[7] >> 4;
975+
dst[32 + 1] = g[7] & 0xff;
976+
dst[32 + 2] = (b[7] & 0xf) << 4 | g[7] >> 8;
977+
dst[32 + 3] = b[7] >> 4;
978+
dst += 36;
979+
}
980+
}
981+
}
982+
void
983+
yuv444p10le_to_r12l(struct from_planar_data d)
984+
{
985+
yuv444pXXle_to_r12l(d, DEPTH10);
986+
}
987+
988+
void
989+
yuv444p12le_to_r12l(struct from_planar_data d)
990+
{
991+
yuv444pXXle_to_r12l(d, DEPTH12);
992+
}
993+
void
994+
yuv444p16le_to_r12l(struct from_planar_data d)
995+
{
996+
yuv444pXXle_to_r12l(d, DEPTH16);
997+
}
998+
#if defined __GNUC__ && !defined __clang__
999+
#pragma GCC pop_options
1000+
#endif
1001+
1002+
[[gnu::always_inline]] static inline void
1003+
yuv444pXXle_to_r10k(struct from_planar_data d, int depth)
1004+
{
1005+
const int width = d.width;
1006+
const size_t height = d.height;
1007+
1008+
assert((uintptr_t) d.in_linesize[0] % 2 == 0);
1009+
assert((uintptr_t) d.in_linesize[1] % 2 == 0);
1010+
assert((uintptr_t) d.in_linesize[2] % 2 == 0);
1011+
1012+
int lmt_rng = d.in_ycbcr_full_rng ? 0 : depth;
1013+
const struct color_coeffs cfs = *get_color_coeffs(d.cs_coeffs, lmt_rng);
1014+
for (size_t y = 0; y < height; ++y) {
1015+
const uint16_t *src_y = (const void *) (d.in_data[0] + (d.in_linesize[0] * y));
1016+
const uint16_t *src_cb = (const void *) (d.in_data[1] + (d.in_linesize[1] * y));
1017+
const uint16_t *src_cr = (const void *) (d.in_data[2] + (d.in_linesize[2] * y));
1018+
unsigned char *dst = d.out_data + (y * d.out_pitch);
1019+
1020+
OPTIMIZED_FOR (int x = 0; x < width; ++x) {
1021+
comp_type_t y = (cfs.y_scale * (*src_y++ - (1<<(depth-4))));
1022+
comp_type_t cr = *src_cr++ - (1<<(depth-1));
1023+
comp_type_t cb = *src_cb++ - (1<<(depth-1));
1024+
1025+
comp_type_t r = YCBCR_TO_R(cfs, y, cb, cr) >> (COMP_BASE-10+depth);
1026+
comp_type_t g = YCBCR_TO_G(cfs, y, cb, cr) >> (COMP_BASE-10+depth);
1027+
comp_type_t b = YCBCR_TO_B(cfs, y, cb, cr) >> (COMP_BASE-10+depth);
1028+
// r g b is now on 10 bit scale
1029+
1030+
r = CLAMP_FULL(r, 10);
1031+
g = CLAMP_FULL(g, 10);
1032+
b = CLAMP_FULL(b, 10);
1033+
1034+
*dst++ = r >> 2;
1035+
*dst++ = (r & 0x3) << 6 | g >> 4;
1036+
*dst++ = (g & 0xF) << 4 | b >> 6;
1037+
*dst++ = (b & 0x3F) << 2 | 0x3U;
1038+
}
1039+
}
1040+
}
1041+
void
1042+
yuv444p10le_to_r10k(struct from_planar_data d)
1043+
{
1044+
yuv444pXXle_to_r10k(d, DEPTH10);
1045+
}
1046+
void
1047+
yuv444p12le_to_r10k(struct from_planar_data d)
1048+
{
1049+
yuv444pXXle_to_r10k(d, DEPTH12);
1050+
}
1051+
void
1052+
yuv444p16le_to_r10k(struct from_planar_data d)
1053+
{
1054+
yuv444pXXle_to_r10k(d, DEPTH16);
1055+
}
1056+
1057+
#define MK_RGBA(r, g, b, alpha_mask, depth) \
1058+
FORMAT_RGBA((r), (g), (b), (d.rgb_shift)[0], (d.rgb_shift)[1], \
1059+
(d.rgb_shift)[2], (alpha_mask), (depth))
1060+
1061+
/**
1062+
* @note
1063+
* Input alpha (if any) is always discarded. This is due to "special" RGB-shifts
1064+
* handling inside UG for output RGBA that makes handling true alpha difficult.
1065+
* In general, we can get rshift=0, gshift=10, bshift=20, meaning that there is
1066+
* no space for alpha. If needed, it could be implemented in an opportunistic
1067+
* way, however, eg. if RGB shifts are the default.
1068+
*/
1069+
[[gnu::always_inline]] static inline void
1070+
yuv444p10le_to_rgb(struct from_planar_data d, bool out_rgba)
1071+
{
1072+
const int width = d.width;
1073+
const size_t height = d.height;
1074+
1075+
enum {
1076+
S_DEPTH = DEPTH10,
1077+
};
1078+
const uint32_t alpha_mask = 0xFFFFFFFFU ^ (0xFFU << d.rgb_shift[0]) ^
1079+
(0xFFU << d.rgb_shift[1]) ^
1080+
(0xFFU << d.rgb_shift[2]);
1081+
int lmt_rng = d.in_ycbcr_full_rng ? 0 : S_DEPTH;
1082+
const struct color_coeffs cfs = *get_color_coeffs(d.cs_coeffs, lmt_rng);
1083+
1084+
for (size_t y = 0; y < height; y++) {
1085+
const uint16_t *src_y = (const void *)(d.in_data[0] + (d.in_linesize[0] * y));
1086+
const uint16_t *src_cb = (const void *)(d.in_data[1] + (d.in_linesize[1] * y));
1087+
const uint16_t *src_cr = (const void *)(d.in_data[2] + (d.in_linesize[2] * y));
1088+
uint8_t *dst = d.out_data + (y * d.out_pitch);
1089+
1090+
OPTIMIZED_FOR (int x = 0; x < width; ++x) {
1091+
comp_type_t cb = *src_cb++ - (1 << (S_DEPTH - 1));
1092+
comp_type_t cr = *src_cr++ - (1 << (S_DEPTH - 1));
1093+
comp_type_t y =
1094+
(*src_y++ - (1 << (S_DEPTH - 4))) * cfs.y_scale;
1095+
comp_type_t r =
1096+
YCBCR_TO_R(cfs, y, cb, cr) >> (COMP_BASE + 2);
1097+
comp_type_t g =
1098+
YCBCR_TO_G(cfs, y, cb, cr) >> (COMP_BASE + 2);
1099+
comp_type_t b =
1100+
YCBCR_TO_B(cfs, y, cb, cr) >> (COMP_BASE + 2);
1101+
if (out_rgba) {
1102+
*(uint32_t *)(void *) dst = MK_RGBA(r, g, b, alpha_mask, 8);
1103+
dst += 4;
1104+
} else {
1105+
*dst++ = CLAMP_FULL(r, 8);
1106+
*dst++ = CLAMP_FULL(g, 8);
1107+
*dst++ = CLAMP_FULL(b, 8);
1108+
}
1109+
}
1110+
}
1111+
}
1112+
void
1113+
yuv444p10le_to_rgb24(struct from_planar_data d)
1114+
{
1115+
yuv444p10le_to_rgb(d, false);
1116+
}
1117+
void
1118+
yuv444p10le_to_rgb32(struct from_planar_data d)
1119+
{
1120+
yuv444p10le_to_rgb(d, true);
1121+
}
1122+

‎src/from_planar.h‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
#ifndef FROM_PLANAR_H_E96E5C5D_6F9C_480D_AD6E_D0AD5149378F
4242
#define FROM_PLANAR_H_E96E5C5D_6F9C_480D_AD6E_D0AD5149378F
4343

44+
#include "color_space.h" // for enum colorspace
45+
#include "compat/c23.h" // IWYU pragma: keep for bool
46+
4447
#ifdef __cplusplus
4548
extern "C" {
4649
#endif // __cplusplus
@@ -67,6 +70,12 @@ struct from_planar_data {
6770
/// set to 1 for Y420 and decode_planar_parallel, otherwise unused
6871
int log2_chroma_h; ///< semantic same as in FF (420 - 1, otherwise 0)
6972
int rgb_shift[3]; ///< relevant only for output RGBA
73+
74+
// currently following 2 parameters are tweaked only for input
75+
// YCbCr->RGB conversion for RGB->YCbCr conversion, these should be
76+
// CS_DFL (0) and false always; both can be safely zero-init
77+
enum colorspace cs_coeffs;
78+
bool in_ycbcr_full_rng;
7079
};
7180

7281
/// functions to decode whole buffer of packed data to planar or packed
@@ -117,12 +126,20 @@ decode_planar_func_t yuv444p10le_to_vuya;
117126
decode_planar_func_t yuv444p12le_to_vuya;
118127
decode_planar_func_t yuv4444p10le_to_y416;
119128
decode_planar_func_t yuv4444p12le_to_y416;
129+
decode_planar_func_t yuv444p10le_to_rgb24;
130+
decode_planar_func_t yuv444p10le_to_rgb32;
131+
decode_planar_func_t yuv444p10le_to_r10k;
132+
decode_planar_func_t yuv444p10le_to_r12l;
120133
decode_planar_func_t yuv444p10le_to_uyvy;
121134
decode_planar_func_t yuv444p10le_to_v210;
122135
decode_planar_func_t yuv444p10le_to_y416;
136+
decode_planar_func_t yuv444p12le_to_r10k;
137+
decode_planar_func_t yuv444p12le_to_r12l;
123138
decode_planar_func_t yuv444p12le_to_uyvy;
124139
decode_planar_func_t yuv444p12le_to_v210;
125140
decode_planar_func_t yuv444p12le_to_y416;
141+
decode_planar_func_t yuv444p16le_to_r10k;
142+
decode_planar_func_t yuv444p16le_to_r12l;
126143
decode_planar_func_t yuv444p16le_to_uyvy;
127144
decode_planar_func_t yuv444p16le_to_v210;
128145
decode_planar_func_t yuv444p16le_to_y416;

0 commit comments

Comments
 (0)