UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
dxt_glsl.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2011-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
44#include <stdlib.h>
45
46#include "gl_context.h"
47
48#include "debug.h"
51#include "host.h"
52#include "lib_common.h"
53#include "module.h"
55#include "video.h"
56#include "video_compress.h"
57
58#include <memory>
59
60using namespace std;
61
62namespace {
63
64struct state_video_compress_rtdxt {
65 struct module module_data;
66
67 struct dxt_encoder **encoder;
68 int encoder_count;
69
70 decoder_t decoder;
71 unique_ptr<char []> decoded;
72 unsigned int configured:1;
73 unsigned int interlaced_input:1;
74 codec_t color_spec;
75
76 int encoder_input_linesize;
77
79
81};
82
83static int configure_with(struct state_video_compress_rtdxt *s, struct video_frame *frame);
84static void dxt_glsl_compress_done(struct module *mod);
85
86static int configure_with(struct state_video_compress_rtdxt *s, struct video_frame *frame)
87{
88 unsigned int x;
89 enum dxt_format format{};
90
91 for (x = 0; x < frame->tile_count; ++x) {
92 if (vf_get_tile(frame, x)->width != vf_get_tile(frame, 0)->width ||
93 vf_get_tile(frame, x)->width != vf_get_tile(frame, 0)->width) {
94
95 fprintf(stderr,"[RTDXT] Requested to compress tiles of different size!");
96 exit_uv(EXIT_FAILURE);
97 return FALSE;
98 }
99 }
100
102 LOG(LOG_LEVEL_NOTICE) << "[RTDXT] Converting from " << get_bits_per_component(frame->color_spec) <<
103 " to 8 bits. You may directly capture 8-bit signal to improve performance.\n";
104 }
105
106 s->decoder = NULL;
107 codec_t codec_try[3] = {};
108 if (s->color_spec == DXT1_YUV) {
109 codec_try[0] = UYVY; // RTDXT doesn't convert RGB to (DXT1_)YUV
111 log_msg(LOG_LEVEL_WARNING, "[RTDXT] Compression of a RGB to DXT1_YUV will use CPU conversion!\n");
112 }
113 } else if (codec_is_a_rgb(frame->color_spec)) {
114 codec_try[0] = RGB;
115 codec_try[1] = RGBA;
116 codec_try[2] = UYVY;
117 } else {
118 codec_try[0] = UYVY;
119 codec_try[1] = RGB;
120 codec_try[2] = RGBA;
121 }
122 for (size_t i = 0; i < sizeof codec_try / sizeof codec_try[0]; ++i) {
123 if ((s->decoder = get_decoder_from_to(frame->color_spec, codec_try[i])) != NULL) {
124 switch (codec_try[i]) {
125 case RGB: format = DXT_FORMAT_RGB; break;
126 case RGBA: format = DXT_FORMAT_RGBA; break;
127 case UYVY: format = DXT_FORMAT_YUV422; break;
128 case VIDEO_CODEC_NONE: break;
129 default: assert(0 && "Shouldn't get other codecs than the above.");
130 }
131 break;
132 }
133 }
134 if (!s->decoder) {
135 fprintf(stderr, "[RTDXT] Unsupported codec: %d\n", frame->color_spec);
136 return FALSE;
137 }
138
139 int data_len = 0;
140
141 s->encoder = (struct dxt_encoder **) calloc(frame->tile_count, sizeof(struct dxt_encoder *));
142 if(s->color_spec == DXT1) {
143 for(int i = 0; i < (int) frame->tile_count; ++i) {
144 s->encoder[i] =
146 s->gl_context.legacy);
147 }
149 } else if(s->color_spec == DXT1_YUV) {
150 for(int i = 0; i < (int) frame->tile_count; ++i) {
151 s->encoder[i] =
153 s->gl_context.legacy);
154 }
155 data_len =
158 } else if(s->color_spec == DXT5){
159 for(int i = 0; i < (int) frame->tile_count; ++i) {
160 s->encoder[i] =
162 s->gl_context.legacy);
163 }
165 }
166 s->encoder_count = frame->tile_count;
167
168 for(int i = 0; i < (int) frame->tile_count; ++i) {
169 if(s->encoder[i] == NULL) {
170 fprintf(stderr, "[RTDXT] Unable to create decoder.\n");
171 exit_uv(EXIT_FAILURE);
172 return FALSE;
173 }
174 }
175
176 s->encoder_input_linesize = frame->tiles[0].width;
177 switch(format) {
178 case DXT_FORMAT_RGBA:
179 s->encoder_input_linesize *= 4;
180 break;
181 case DXT_FORMAT_RGB:
182 s->encoder_input_linesize *= 3;
183 break;
185 s->encoder_input_linesize *= 2;
186 break;
187 case DXT_FORMAT_YUV:
188 /* not used - just not compilator to complain */
189 abort();
190 break;
191 }
192
193 assert(data_len > 0);
194 assert(s->encoder_input_linesize > 0);
195
196 struct video_desc compressed_desc;
197 compressed_desc = video_desc_from_frame(frame);
198 compressed_desc.color_spec = s->color_spec;
199 /* We will deinterlace the output frame */
201 compressed_desc.interlacing = PROGRESSIVE;
202 s->interlaced_input = TRUE;
203 fprintf(stderr, "[DXT compress] Enabling automatic deinterlacing.\n");
204 } else {
205 s->interlaced_input = FALSE;
206 }
207 s->pool.reconfigure(compressed_desc, data_len);
208
209 s->decoded = unique_ptr<char []>(new char[4 * compressed_desc.width * compressed_desc.height]);
210
211 s->configured = TRUE;
212 return TRUE;
213}
214
215struct module *dxt_glsl_compress_init(struct module *parent, const char *opts)
216{
217 struct state_video_compress_rtdxt *s;
218
219 if(strcmp(opts, "help") == 0) {
220 printf("DXT GLSL comperssion usage:\n");
221 printf("\t-c RTDXT:DXT1\n");
222 printf("\t\tcompress with DXT1\n");
223 printf("\t-c RTDXT:DXT1_YUV\n");
224 printf("\t\tcompress with DXT1_YUV\n");
225 printf("\t-c RTDXT:DXT5\n");
226 printf("\t\tcompress with DXT5 YCoCg\n");
227 return static_cast<module*>(INIT_NOERR);
228 }
229
230 s = new state_video_compress_rtdxt();
231
232 if (strcasecmp(opts, "DXT5") == 0) {
233 s->color_spec = DXT5;
234 } else if (strcasecmp(opts, "DXT1") == 0) {
235 s->color_spec = DXT1;
236 } else if (strcasecmp(opts, "DXT1_YUV") == 0) {
237 s->color_spec = DXT1_YUV;
238 } else if (opts[0] == '\0') {
239 s->color_spec = DXT1;
240 } else {
241 fprintf(stderr, "Unknown compression: %s\n", opts);
242 delete s;
243 return NULL;
244 }
245
246 if(!init_gl_context(&s->gl_context, GL_CONTEXT_ANY)) {
247 fprintf(stderr, "[RTDXT] Error initializing GL context");
248 delete s;
249 return NULL;
250 }
251
253
254 module_init_default(&s->module_data);
255 s->module_data.cls = MODULE_CLASS_DATA;
256 s->module_data.priv_data = s;
257 s->module_data.deleter = dxt_glsl_compress_done;
258 module_register(&s->module_data, parent);
259
260 return &s->module_data;
261}
262
263shared_ptr<video_frame> dxt_glsl_compress(struct module *mod, shared_ptr<video_frame> tx)
264{
265 if (!tx) {
266 return {};
267 }
268
269 struct state_video_compress_rtdxt *s = (struct state_video_compress_rtdxt *) mod->priv_data;
270 int i;
271 unsigned char *line1, *line2;
272
273 unsigned int x;
274
275 gl_context_make_current(&s->gl_context);
276
277 if(!s->configured) {
278 int ret;
279 ret = configure_with(s, tx.get());
280 if(!ret)
281 return NULL;
282 }
283
284 shared_ptr<video_frame> out_frame = s->pool.get_frame();
285
286 for (x = 0; x < tx->tile_count; ++x) {
287 struct tile *in_tile = vf_get_tile(tx.get(), x);
288 struct tile *out_tile = vf_get_tile(out_frame.get(), x);
289
290 line1 = (unsigned char *) in_tile->data;
291 line2 = (unsigned char *) s->decoded.get();
292
293 for (i = 0; i < (int) in_tile->height; ++i) {
294 s->decoder(line2, line1, s->encoder_input_linesize,
295 0, 8, 16);
296 line1 += vc_get_linesize(in_tile->width, tx->color_spec);
297 line2 += s->encoder_input_linesize;
298 }
299
300 if(s->interlaced_input)
301 vc_deinterlace((unsigned char *) s->decoded.get(), s->encoder_input_linesize,
302 in_tile->height);
303
304 dxt_encoder_compress(s->encoder[x],
305 (unsigned char *) s->decoded.get(),
306 (unsigned char *) out_tile->data);
307 }
308
310
311 return out_frame;
312}
313
314static void dxt_glsl_compress_done(struct module *mod)
315{
316 struct state_video_compress_rtdxt *s = (struct state_video_compress_rtdxt *) mod->priv_data;
317
318 if(s->encoder) {
319 for(int i = 0; i < s->encoder_count; ++i) {
320 if(s->encoder[i])
321 dxt_encoder_destroy(s->encoder[i]);
322 }
323 }
324
325 destroy_gl_context(&s->gl_context);
326 delete s;
327}
328
329const struct video_compress_info rtdxt_info = {
330 "RTDXT",
331 dxt_glsl_compress_init,
332 dxt_glsl_compress,
333 NULL,
334 NULL,
335 NULL,
336 NULL,
337 NULL,
338 NULL
339};
340
342
343} // end of anonymous namespace
344
struct video_frame * frame
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
int vc_get_linesize(unsigned int width, codec_t codec)
#define TRUE
#define FALSE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG(level)
Definition debug.h:313
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
dxt_format
Definition dxt_common.h:78
@ DXT_FORMAT_RGBA
Definition dxt_common.h:80
@ DXT_FORMAT_YUV
Definition dxt_common.h:81
@ DXT_FORMAT_YUV422
Definition dxt_common.h:82
@ DXT_FORMAT_RGB
Definition dxt_common.h:79
@ DXT_TYPE_DXT1_YUV
Definition dxt_common.h:90
@ DXT_TYPE_DXT1
Definition dxt_common.h:89
@ DXT_TYPE_DXT5_YCOCG
Definition dxt_common.h:91
int dxt_encoder_compress(struct dxt_encoder *encoder, DXT_IMAGE_TYPE *image, unsigned char *image_compressed)
struct dxt_encoder * dxt_encoder_create(enum dxt_type type, int width, int height, enum dxt_format format, int legacy)
int dxt_encoder_destroy(struct dxt_encoder *encoder)
static int dxt_get_size(int width, int height, enum dxt_type format)
Definition dxt_util.h:60
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
#define GL_CONTEXT_ANY
Definition gl_context.h:72
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
void exit_uv(int status)
Definition host.cpp:625
#define INIT_NOERR
Definition host.h:73
@ 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
decoder_t get_decoder_from_to(codec_t in, codec_t out)
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
const char * parent
Definition settings.cpp:198
enum dxt_format format
Definition dxt_encoder.c:88
unsigned legacy
Definition gl_context.h:66
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
enum interlacing_t interlacing
Definition types.h:307
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
unsigned int tile_count
Definition types.h:344
codec_t color_spec
Definition types.h:306
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
codec_t
Definition types.h:65
@ DXT1
S3 Texture Compression DXT1.
Definition types.h:77
@ 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
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ DXT5
S3 Texture Compression DXT5.
Definition types.h:79
@ DXT1_YUV
Structure same as DXT1, instead of RGB, YCbCr values are stored.
Definition types.h:78
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
This is an umbrella header for video functions.
void vc_deinterlace(unsigned char *src, long src_linesize, int lines)
Deinterlaces framebuffer.
bool codec_is_a_rgb(codec_t codec)
Returns TRUE if specified pixelformat is some form of RGB (not YUV).
int get_bits_per_component(codec_t codec)
static bool configure_with(struct state_video_compress_cineform *s, struct video_desc desc)
Definition cineform.cpp:243
API for video compress drivers.
struct tile * vf_get_tile(struct video_frame *buf, int pos)
Returns pointer to n-th tile from video frame Equivalent to &video_frame::tiles[pos].