UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
uyvy.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#endif // HAVE_CONFIG_H
43#include "debug.h"
44#include "host.h"
45#include "lib_common.h"
46#include "module.h"
48#include "video_compress.h"
49#include "video.h"
50#include <stdlib.h>
51
52#include "gl_context.h"
53
54using namespace std;
55
56namespace {
57
58static const char fp_display_rgba_to_yuv422_legacy[] =
59"#define LEGACY 1\n"
60 "#if LEGACY\n"
61 "#define TEXCOORD gl_TexCoord[0]\n"
62 "#else\n"
63 "#define TEXCOORD TEX0\n"
64 "#define texture2D texture\n"
65 "#endif\n"
66 "\n"
67 "#if LEGACY\n"
68 "#define colorOut gl_FragColor\n"
69 "#else\n"
70 "out vec4 colorOut;\n"
71 "#endif\n"
72 "\n"
73 "#if ! LEGACY\n"
74 "in vec4 TEX0;\n"
75 "#endif\n"
76 "\n"
77 "uniform sampler2D image;\n"
78 "uniform float imageWidth; // is original image width, it means twice as wide as ours\n"
79 "\n"
80 "void main()\n"
81 "{\n"
82 " vec4 rgba1, rgba2;\n"
83 " vec4 yuv1, yuv2;\n"
84 " vec2 coor1, coor2;\n"
85 " float U, V;\n"
86 "\n"
87 " coor1 = TEXCOORD.xy - vec2(1.0 / (imageWidth * 2.0), 0.0);\n"
88 " coor2 = TEXCOORD.xy + vec2(1.0 / (imageWidth * 2.0), 0.0);\n"
89 "\n"
90 " rgba1 = texture2D(image, coor1);\n"
91 " rgba2 = texture2D(image, coor2);\n"
92 " \n"
93 " yuv1.x = 1.0/16.0 + (rgba1.r * 0.2126 + rgba1.g * 0.7152 + rgba1.b * 0.0722) * 0.8588; // Y\n"
94 " yuv1.y = 0.5 + (-rgba1.r * 0.1145 - rgba1.g * 0.3854 + rgba1.b * 0.5) * 0.8784;\n"
95 " yuv1.z = 0.5 + (rgba1.r * 0.5 - rgba1.g * 0.4541 - rgba1.b * 0.0458) * 0.8784;\n"
96 " \n"
97 " yuv2.x = 1.0/16.0 + (rgba2.r * 0.2126 + rgba2.g * 0.7152 + rgba2.b * 0.0722) * 0.8588; // Y\n"
98 " yuv2.y = 0.5 + (-rgba2.r * 0.1145 - rgba2.g * 0.3854 + rgba2.b * 0.5) * 0.8784;\n"
99 " yuv2.z = 0.5 + (rgba2.r * 0.5 - rgba2.g * 0.4541 - rgba2.b * 0.0458) * 0.8784;\n"
100 " \n"
101 " U = mix(yuv1.y, yuv2.y, 0.5);\n"
102 " V = mix(yuv1.z, yuv2.z, 0.5);\n"
103 " \n"
104 " colorOut = vec4(U,yuv1.x, V, yuv2.x);\n"
105 "}\n"
106;
107
108
109struct state_video_compress_uyvy {
110 struct module module_data;
111
112 unsigned int configured:1;
113 struct video_desc saved_desc;
114
115 struct gl_context context;
116
117 GLuint program_rgba_to_yuv422;
118
119 GLuint texture_rgba;
120 GLuint fbo;
121 GLuint texture;
122
123 int gl_format;
124
125 video_frame_pool *pool;
126};
127
128int uyvy_configure_with(struct state_video_compress_uyvy *s, struct video_frame *tx);
129static void uyvy_compress_done(struct module *mod);
130
131struct module * uyvy_compress_init(struct module *parent, const char *)
132{
133 struct state_video_compress_uyvy *s;
134
135 s = (struct state_video_compress_uyvy *) malloc(sizeof(struct state_video_compress_uyvy));
136
137 if(!init_gl_context(&s->context, GL_CONTEXT_LEGACY))
138 abort();
139
140 glEnable(GL_TEXTURE_2D);
141
142 s->program_rgba_to_yuv422 = glsl_compile_link(NULL, fp_display_rgba_to_yuv422_legacy);
143 if (!s->program_rgba_to_yuv422) {
144 log_msg(LOG_LEVEL_ERROR, "UYVY: Unable to create shader!\n");
145 free(s);
146 return NULL;
147 }
148
149 glUseProgram(s->program_rgba_to_yuv422);
150 glUniform1i(glGetUniformLocation(s->program_rgba_to_yuv422,"image"),0);
151 glUseProgram(0);
152
153 s->configured = FALSE;
154
156
157 s->pool = new video_frame_pool();
158
159 module_init_default(&s->module_data);
160 s->module_data.cls = MODULE_CLASS_DATA;
161 s->module_data.priv_data = s;
162 s->module_data.deleter = uyvy_compress_done;
163 module_register(&s->module_data, parent);
164
165 return &s->module_data;
166}
167
168int uyvy_configure_with(struct state_video_compress_uyvy *s, struct video_frame *tx)
169{
170 switch (tx->color_spec) {
171 case RGB:
172 s->gl_format = GL_RGB;
173 break;
174 case RGBA:
175 s->gl_format = GL_RGBA;
176 break;
177 default:
178 fprintf(stderr, "[UYVY compress] We can transform only RGB or RGBA to UYVY.\n");
179 return FALSE;
180 }
181
182 struct video_desc compressed_desc;
183 compressed_desc = video_desc_from_frame(tx);
184 compressed_desc.color_spec = UYVY;
185 s->pool->reconfigure(compressed_desc, 2 * compressed_desc.width *
186 compressed_desc.height /* UYVY */);
187
188 glUseProgram(s->program_rgba_to_yuv422);
189 glUniform1f(glGetUniformLocation(s->program_rgba_to_yuv422, "imageWidth"),
190 (GLfloat) tx->tiles[0].width);
191 glUseProgram(0);
192
193 glGenFramebuffers(1, &s->fbo);
194
195 glGenTextures(1, &s->texture_rgba);
196 glBindTexture(GL_TEXTURE_2D, s->texture_rgba);
197 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
198 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
199 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
200 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
201 glTexImage2D(GL_TEXTURE_2D, 0 , s->gl_format, tx->tiles[0].width, tx->tiles[0].height, 0, s->gl_format, GL_UNSIGNED_BYTE, 0);
202
203 glGenTextures(1, &s->texture);
204 glBindTexture(GL_TEXTURE_2D, s->texture);
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
207 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
209 glTexImage2D(GL_TEXTURE_2D, 0 , GL_RGBA, tx->tiles[0].width / 2, tx->tiles[0].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
210
211 glBindTexture(GL_TEXTURE_2D, 0);
212
213 glClearColor(1.0,1.0,0,1.0);
214
215 glMatrixMode( GL_PROJECTION );
216 glLoadIdentity( );
217 glOrtho(-1,1,-1,1,10,-10);
218
219 glMatrixMode( GL_MODELVIEW );
220 glLoadIdentity( );
221
222 glViewport( 0, 0, tx->tiles[0].width / 2, tx->tiles[0].height);
223
224 s->configured = TRUE;
225 s->saved_desc = video_desc_from_frame(tx);
226
227 return true;
228}
229
230shared_ptr<video_frame> uyvy_compress(struct module *mod, shared_ptr<video_frame> tx)
231{
232 if (!tx) {
233 return {};
234 }
235 struct state_video_compress_uyvy *s = (struct state_video_compress_uyvy *) mod->priv_data;
236
237 gl_context_make_current(&s->context);
238
239 if(!s->configured) {
240 int ret;
241 ret = uyvy_configure_with(s, tx.get());
242 if(!ret)
243 return NULL;
244 }
245
246 assert(video_desc_eq(video_desc_from_frame(tx.get()), s->saved_desc));
247
248 shared_ptr<video_frame> out = s->pool->get_frame();
249 struct tile *tile = &out->tiles[0];
250
251 glBindTexture(GL_TEXTURE_2D, s->texture_rgba);
252 glTexSubImage2D(GL_TEXTURE_2D,
253 0,
254 0,
255 0,
256 tx->tiles[0].width,
257 tx->tiles[0].height,
258 s->gl_format,
259 GL_UNSIGNED_BYTE,
260 tx->tiles[0].data);
261
262 glBindFramebuffer(GL_FRAMEBUFFER, s->fbo);
263 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, s->texture, 0);
264
265 glBindTexture(GL_TEXTURE_2D, s->texture_rgba); /* to texturing unit 0 */
266
267 glUseProgram(s->program_rgba_to_yuv422);
268
269 glBegin(GL_QUADS);
270 glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
271 glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
272 glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
273 glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
274 glEnd();
275
276 // Read back
277 glReadBuffer(GL_COLOR_ATTACHMENT0);
278 glReadPixels(0, 0, tile->width / 2, tile->height, GL_RGBA, GL_UNSIGNED_BYTE, tile->data);
279
280 glUseProgram(0);
281 glBindTexture(GL_TEXTURE_2D, 0);
282 glBindFramebuffer(GL_FRAMEBUFFER, 0);
283
285
286 return out;
287}
288
289static void uyvy_compress_done(struct module *mod)
290{
291 struct state_video_compress_uyvy *s = (struct state_video_compress_uyvy *) mod->priv_data;
292
293 glDeleteFramebuffers(1, &s->fbo);
294 glDeleteTextures(1, &s->texture_rgba);
295 glDeleteTextures(1, &s->texture);
296 destroy_gl_context(&s->context);
297
298 delete s->pool;
299
300 free(s);
301}
302
303const struct video_compress_info uyvy_info = {
304 "UYVY",
305 uyvy_compress_init,
306 uyvy_compress,
307 NULL,
308 NULL,
309 NULL,
310 NULL,
311 NULL,
312 NULL
313};
314
316
317} // end of anonymous namespace
318
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
#define TRUE
#define FALSE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
bool init_gl_context(struct gl_context *context, int which)
initializes specified OpenGL context
Definition gl_context.c:69
void destroy_gl_context(struct gl_context *context)
Definition gl_context.c:223
void gl_context_make_current(struct gl_context *context)
Definition gl_context.c:236
GLuint glsl_compile_link(const char *vprogram, const char *fprogram)
Definition gl_context.c:147
#define GL_CONTEXT_LEGACY
Definition gl_context.h:73
void module_init_default(struct module *module_data)
Definition module.c:48
void module_register(struct module *module_data, struct module *parent)
Definition module.c:82
@ MODULE_CLASS_DATA
Definition module.h:86
#define VIDEO_COMPRESS_ABI_VERSION
@ LIBRARY_CLASS_VIDEO_COMPRESS
Definition lib_common.h:82
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
const char * parent
Definition settings.cpp:198
enum module_class cls
Definition module.h:115
void * priv_data
Definition module.h:126
module_deleter_t deleter
Definition module.h:118
Struct tile is an area of video_frame.
Definition types.h:279
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int height
Definition types.h:281
std::shared_ptr< video_frame > get_frame()
void reconfigure(struct video_desc new_desc, size_t new_size=SIZE_MAX)
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
static const char fp_display_rgba_to_yuv422_legacy[]
Definition syphon.m:76
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
This is an umbrella header for video functions.
API for video compress drivers.
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.