46#define MOD_NAME "[GL conversions] "
52layout(location = 0) in vec2 vert_pos;
53layout(location = 1) in vec2 vert_uv;
57uniform vec2 scale_vec;
60 gl_Position = vec4(vert_pos, 0.0f, 1.0f);
65static const char *yuv_conv_frag_src = R
"END(
67layout(location = 0) out vec4 color;
73uniform float luma_scale = 1.1643f;
74uniform float r_cr = 1.7926f;
75uniform float g_cb = -0.2132f;
76uniform float g_cr = -0.5328f;
77uniform float b_cb = 2.1124f;
80 //The width could be odd, but the width of texture is always even
81 float textureWidth = float((int(width) + 1) / 2 * 2);
83 yuv.rgba = texture(tex, vec2(UV.x / textureWidth * width, UV.y)).grba;
84 if(UV.x * width / 2.0 - floor(UV.x * width / 2.0) > 0.5)
87 yuv.r = 1.1643 * (yuv.r - 0.0625);
91 color.r = yuv.r + r_cr * yuv.b;
92 color.g = yuv.r + g_cb * yuv.g + g_cr * yuv.b;
93 color.b = yuv.r + b_cb * yuv.g;
98static void load_yuv_coefficients(
GlProgram& program){
103 int color = std::stol(
col,
nullptr, 16) >> 4;
104 if (color < 1 || color > 3){
110 double kr = cs_coeffs[2 * color];
111 double kb = cs_coeffs[2 * color + 1];
113 glUseProgram(program.
get());
114 GLuint loc = glGetUniformLocation(program.
get(),
"luma_scale");
116 loc = glGetUniformLocation(program.
get(),
"r_cr");
117 glUniform1f(loc,
R_CR(8, kr, kb));
118 loc = glGetUniformLocation(program.
get(),
"g_cr");
119 glUniform1f(loc,
G_CR(8, kr, kb));
120 loc = glGetUniformLocation(program.
get(),
"g_cb");
121 glUniform1f(loc,
G_CB(8, kr, kb));
122 loc = glGetUniformLocation(program.
get(),
"b_cb");
123 glUniform1f(loc,
B_CB(8, kr, kb));
132 width_uniform_location = glGetUniformLocation(program.
get(),
"width");
135 virtual ~Rendering_convertor() { };
137 void attach_texture(
Texture& tex)
override final {
138 fbuf.attach_texture(tex);
141 void put_frame(
video_frame *f,
bool pbo_frame)
override final{
142 glUseProgram(program.
get());
143 glBindFramebuffer(GL_FRAMEBUFFER, fbuf.get());
145 glClear(GL_COLOR_BUFFER_BIT);
147 prepare_input_tex(f, pbo_frame);
149 if(width_uniform_location != -1)
150 glUniform1f(width_uniform_location, f->
tiles[0].
width);
154 glBindFramebuffer(GL_FRAMEBUFFER, 0);
159 virtual void prepare_input_tex(
video_frame *f,
bool pbo_frame) = 0;
164 GLint width_uniform_location = -1;
171 void attach_texture(
Texture& tex)
override final{
179class Yuv_convertor :
public Rendering_convertor{
181 Yuv_convertor() : Rendering_convertor(
vert_src, yuv_conv_frag_src){
182 load_yuv_coefficients(program);
186 void prepare_input_tex(
video_frame *f,
bool pbo_frame)
override final{
190 input_tex.load_frame(w, h, GL_RGBA,
191 GL_RGBA, GL_UNSIGNED_BYTE,
201layout(location = 0) out vec4 color;
203uniform sampler2D tex;
207uniform float luma_scale = 1.1643f;
208uniform float r_cr = 1.7926f;
209uniform float g_cb = -0.2132f;
210uniform float g_cr = -0.5328f;
211uniform float b_cb = 2.1124f;
214const vec3 yuvOffset = vec3(-0.0625, -0.5, -0.5);
217vec3 Rcoeff = vec3(luma_scale, 0.0, r_cr);
218vec3 Gcoeff = vec3(luma_scale, g_cb, g_cr);
219vec3 Bcoeff = vec3(luma_scale, b_cb, 0.0);
221// U Y V A | Y U Y A | V Y U A | Y V Y A
223int GROUP_FOR_INDEX(int i) {
227int SUBINDEX_FOR_INDEX(int i) {
240 return 4 * (i / 2) + 2;
247vec3 ycbcr2rgb(vec3 yuvToConvert) {
249 yuvToConvert += yuvOffset;
250 pix.r = dot(yuvToConvert, Rcoeff);
251 pix.g = dot(yuvToConvert, Gcoeff);
252 pix.b = dot(yuvToConvert, Bcoeff);
257 float imageWidthRaw; // v210 texture size
258 imageWidthRaw = float((int(width) + 47) / 48 * 32); // 720->480
260 // interpolate (0,1) texcoords to [0,719]
262 texcoordDenormX = int(round(UV.x * width - .5));
264 // 0 1 1 2 3 3 4 5 5 6 7 7 etc.
266 yOffset = offset(_y(texcoordDenormX));
267 int sourceColumnIndexY;
268 sourceColumnIndexY = GROUP_FOR_INDEX(yOffset);
270 // 0 0 1 1 2 2 4 4 5 5 6 6 etc.
272 uOffset = offset(_u(texcoordDenormX));
273 int sourceColumnIndexU;
274 sourceColumnIndexU = GROUP_FOR_INDEX(uOffset);
276 // 0 0 2 2 3 3 4 4 6 6 7 7 etc.
278 vOffset = offset(_v(texcoordDenormX));
279 int sourceColumnIndexV;
280 sourceColumnIndexV = GROUP_FOR_INDEX(vOffset);
282 // 1 0 2 1 0 2 1 0 2 etc.
284 compY = SUBINDEX_FOR_INDEX(yOffset);
286 // 0 0 1 1 2 2 0 0 1 1 2 2 etc.
288 compU = SUBINDEX_FOR_INDEX(uOffset);
290 // 2 2 0 0 1 1 2 2 0 0 1 1 etc.
292 compV = SUBINDEX_FOR_INDEX(vOffset);
297 y = texture(tex, vec2((float(sourceColumnIndexY) + .5) / imageWidthRaw, UV.y));
298 u = texture(tex, vec2((float(sourceColumnIndexU) + .5) / imageWidthRaw, UV.y));
299 v = texture(tex, vec2((float(sourceColumnIndexV) + .5) / imageWidthRaw, UV.y));
301 vec3 outColor = ycbcr2rgb(vec3(y[compY], u[compU], v[compV]));
303 color = vec4(outColor, 1.0);
307class V210_convertor :
public Rendering_convertor{
311 load_yuv_coefficients(program);
315 void prepare_input_tex(
video_frame *f,
bool pbo_frame =
false)
override final{
318 input_tex.load_frame(w, h, GL_RGB10_A2,
319 GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV,
327layout(location = 0) out vec4 color;
329uniform sampler2D tex;
331uniform float luma_scale = 1.1643f;
332uniform float r_cr = 1.7926f;
333uniform float g_cb = -0.2132f;
334uniform float g_cr = -0.5328f;
335uniform float b_cb = 2.1124f;
339 yuv.rgba = texture(tex, UV).grba;
340 yuv.r = luma_scale * (yuv.r - 0.0625);
343 color.r = yuv.r + r_cr * yuv.b;
344 color.g = yuv.r + g_cb * yuv.g + g_cr * yuv.b;
345 color.b = yuv.r + b_cb * yuv.g;
350class Y416_convertor :
public Rendering_convertor{
354 load_yuv_coefficients(program);
358 void prepare_input_tex(
video_frame *f,
bool pbo_frame =
false)
override final{
361 input_tex.load_frame(w, h, GL_RGBA,
362 GL_RGBA, GL_UNSIGNED_SHORT,
367class DXT1_convertor :
public Loading_convertor{
372 glBindTexture(GL_TEXTURE_2D, tex->get());
373 glCompressedTexImage2D(GL_TEXTURE_2D, 0,
374 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
384layout(location = 0) out vec4 color;
386uniform sampler2D tex;
390 vec4 element = texture(tex, UV);
391 float scale = (element.z * ( 255.0 / 8.0 )) + 1.0;
392 float Co = (element.x - (0.5 * 256.0 / 255.0)) / scale;
393 float Cg = (element.y - (0.5 * 256.0 / 255.0)) / scale;
395 color = vec4(Y + Co - Cg, Y + Cg, Y - Co - Cg, 1.0);
399class DXT5_convertor :
public Rendering_convertor{
404 void prepare_input_tex(
video_frame *f,
bool)
override final{
407 input_tex.allocate();
408 glBindTexture(GL_TEXTURE_2D, input_tex.get());
409 glCompressedTexImage2D(GL_TEXTURE_2D, 0,
410 GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
420layout(location = 0) out vec4 color;
422uniform sampler2D tex;
425 vec4 col = texture(tex, UV);
427 float Y = 1.1643 * (col[0] - 0.0625);
428 float U = (col[1] - 0.5);
429 float V = (col[2] - 0.5);
431 float R = Y + 1.7926 * V;
432 float G = Y - 0.2132 * U - 0.5328 * V;
433 float B = Y + 2.1124 * U;
435 color = vec4(R,G,B,1.0);
439class DXT1_YUV_convertor :
public Rendering_convertor{
444 void prepare_input_tex(
video_frame *f,
bool)
override final{
447 input_tex.allocate();
448 glBindTexture(GL_TEXTURE_2D, input_tex.get());
449 glCompressedTexImage2D(GL_TEXTURE_2D, 0,
450 GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
457class R10k_convertor :
public Loading_convertor{
459 void put_frame(
video_frame *f,
bool =
false)
override{
462 uint32_t *dst =
nullptr;
463 int data_len = w * h * 8;
464 char *tex_src_data =
nullptr;
466 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, internal_pbo->get());
467 glBufferData(GL_PIXEL_UNPACK_BUFFER, data_len, 0, GL_STREAM_DRAW);
468 dst = (uint32_t *) glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
469 process_r10k(dst,
reinterpret_cast<uint32_t *
>(f->
tiles[0].
data), w, h);
470 tex_src_data =
nullptr;
471 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
473 scratchpad.resize(w * h * 8);
474 dst =
reinterpret_cast<uint32_t *
>(scratchpad.data());
475 tex_src_data = scratchpad.data();
476 process_r10k(dst,
reinterpret_cast<uint32_t *
>(f->
tiles[0].
data), w, h);
479 glBindTexture(GL_TEXTURE_2D, tex->get());
480 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, tex_src_data);
483 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
488 void process_r10k(uint32_t * __restrict out,
const uint32_t *__restrict in,
long width,
long height) {
490 for (
long i = 0; i < height; i += 1) {
494 (x & 0xFFU) << 2U | (x & 0xC0'00U) >> 14U |
495 (x & 0x3F'00U) << 6U | (x & 0xF0'00'00) >> 10U |
496 (x & 0x0F'00'00U) << 10U | (x & 0xFC'00'00'00U) >> 6U;
498 in += line_padding_b /
sizeof(uint32_t);
501 std::vector<char> scratchpad;
504class RGB_convertor :
public Loading_convertor{
506 void put_frame(
video_frame *f,
bool pbo_frame =
false)
override{
509 tex->load_frame(w, h, GL_RGB,
510 GL_RGB, GL_UNSIGNED_BYTE,
515class RGBA_convertor :
public Loading_convertor{
517 void put_frame(
video_frame *f,
bool pbo_frame =
false)
override{
520 tex->load_frame(w, h, GL_RGBA,
521 GL_RGBA, GL_UNSIGNED_BYTE,
526static const char fp_passthrough[] = R
"raw(
529layout(location = 0) out vec4 color;
531uniform sampler2D tex;
535 color = texture(tex, UV);
540class VDPAU_convertor :
public Rendering_convertor{
542 VDPAU_convertor(): Rendering_convertor(
vert_src, fp_passthrough) {
551 void prepare_input_tex(
video_frame *f,
bool =
false)
override{
552 vdp.loadFrame(
reinterpret_cast<hw_vdpau_frame *
>(f->
tiles[0].
data));
555 struct state_vdpau vdp;
561 std::unique_ptr<Frame_convertor> (*construct_func)();
562} codec_convertor_map[]{
580 for(
const auto& i : codec_convertor_map){
582 return i.construct_func();
589 std::vector<codec_t> ret;
590 ret.reserve(std::size(codec_convertor_map));
591 for(
const auto& i : codec_convertor_map){
592 ret.push_back(i.codec);
int vc_get_linesize(unsigned int width, codec_t codec)
static std::unique_ptr< Frame_convertor > construct_unique()
#define G_CR(in_depth, kr, kb)
#define B_CB(in_depth, kr, kb)
#define R_CR(in_depth, kr, kb)
#define Y_LIMIT_INV(in_depth)
#define G_CB(in_depth, kr, kb)
#define LOG_LEVEL_WARNING
less severe errors
static const char * fp_display_dxt1_yuv
static const char fp_display_dxt5ycocg[]
static const char * v210_to_rgb_fp
static const char * yuva_to_rgb_fp
const char * get_commandline_param(const char *key)
std::vector< codec_t > get_convertor_supported_codecs()
std::unique_ptr< Frame_convertor > get_convertor_for_codec(codec_t codec)
char * data
Raw tile data. Pointer must be at least 4B aligned.
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
@ DXT1
S3 Texture Compression DXT1.
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
@ RGB
RGB 8-bit (packed into 24-bit word)
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
@ HW_VDPAU
VDPAU hardware surface.
@ Y416
interleaved little-endian YCbCr 4444 16-bit - UYVA
@ DXT5
S3 Texture Compression DXT5.
@ RGBA
RGBA 8-bit, big-endian.
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...