UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
matrix.c
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2020-2021 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 "capture_filter.h"
45#include "debug.h"
46#include "lib_common.h"
47#include "utils/color_out.h"
48#include "utils/macros.h"
49#include "video.h"
50#include "video_codec.h"
52
53#define MOD_NAME "[matrix cap. f.] "
54
60
61static int init(struct module *parent, const char *cfg, void **state)
62{
64
65 if (strlen(cfg) == 0 || strcmp(cfg, "help") == 0) {
66 printf("Performs matrix transformation on input pixels.\n\n"
67 "usage:\n");
68 color_printf(TERM_BOLD "\t--capture-filter matrix:a:b:c:d:e:f:g:h:i[:no-bounds-check]\n" TERM_RESET);
69 printf("where numbers a-i are members of 3x3 transformation matrix [a b c; d e f; g h i], decimals.\n"
70 "Coefficients are applied at unpacked pixels (eg. on Y Cb and Cr channels of UYVY). Result is marked as RGB.\n"
71 "Currently only RGB and UYVY is supported on input. No additional color transformation is performed.\n");
72 printf("\nOptional \"no-bounds-check\" options disables check for overflows/underflows which improves performance\n"
73 "but may give incorrect results if operation oveflows or underflows.\n");
74 return 1;
75 }
76 struct state_capture_filter_matrix *s = calloc(1, sizeof(struct state_capture_filter_matrix));
77 s->check_bounds = true;
78 char *cfg_c = strdup(cfg);
79 char *item = NULL;
80 char *save_ptr = NULL;
81 char *tmp = cfg_c;
82 int i = 0;
83 while ((item = strtok_r(tmp, ":", &save_ptr)) != NULL) {
84 if (i == 9) {
85 if (strcmp(item, "no-bound-check") == 0) {
86 s->check_bounds = false;
87 } else {
88 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Excess initializer given: %s\n", item);
89 }
90 break;
91 }
92 char *endptr = NULL;
93 errno = 0;
94 s->transform_matrix[i++] = strtod(item, &endptr);
95 if (errno != 0 || *endptr != '\0') {
96 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Problem converting number %s\n", item);
97 }
98 tmp = NULL;
99 }
100 free(cfg_c);
101
102 if (i != 9) {
103 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Not enough numbers for transformation matrix - expected: 9, got: %d\n", i);
104 free(s);
105 return -1;
106 }
107
108 *state = s;
109 return 0;
110}
111
112static void done(void *state)
113{
114 free(state);
115}
116
117static struct video_frame *filter(void *state, struct video_frame *in)
118{
121 if (in->color_spec == UYVY) {
123 }
124 struct video_frame *out = vf_alloc_desc(desc);
125 if (s->vo_pp_out_buffer) {
126 out->tiles[0].data = s->vo_pp_out_buffer;
127 } else {
128 out->tiles[0].data = malloc(out->tiles[0].data_len);
130 }
132
133 if (s->check_bounds) {
134 if (in->color_spec == UYVY) {
135 unsigned char *in_data = (unsigned char *) in->tiles[0].data;
136 unsigned char *out_data = (unsigned char *) out->tiles[0].data;
137
138 for (unsigned int i = 0; i < in->tiles[0].data_len; i += 4) {
139 double a[3];
140 double b[3];
141 a[1] = b[1] = *in_data++;
142 a[0] = *in_data++;
143 a[2] = b[2] = *in_data++;
144 b[0] = *in_data++;
145 int val = s->transform_matrix[0] * (a[0] - 16) +
146 s->transform_matrix[1] * (a[1] - 128) +
147 s->transform_matrix[2] * (a[2] - 128);
148 *out_data++ = CLAMP(val, 0, 255);
149 val = s->transform_matrix[3] * (a[0] - 16) +
150 s->transform_matrix[4] * (a[1] - 128) +
151 s->transform_matrix[5] * (a[2] - 128);
152 *out_data++ = CLAMP(val, 0, 255);
153 val = s->transform_matrix[6] * (a[0] - 16) +
154 s->transform_matrix[7] * (a[1] - 128) +
155 s->transform_matrix[8] * (a[2] - 128);
156 *out_data++ = CLAMP(val, 0, 255);
157 val = s->transform_matrix[0] * (b[0] - 16) +
158 s->transform_matrix[1] * (b[1] - 128) +
159 s->transform_matrix[2] * (b[2] - 128);
160 *out_data++ = CLAMP(val, 0, 255);
161 val = s->transform_matrix[3] * (b[0] - 16) +
162 s->transform_matrix[4] * (b[1] - 128) +
163 s->transform_matrix[5] * (b[2] - 128);
164 *out_data++ = CLAMP(val, 0, 255);
165 val = s->transform_matrix[6] * (b[0] - 16) +
166 s->transform_matrix[7] * (b[1] - 128) +
167 s->transform_matrix[8] * (b[2] - 128),
168 *out_data++ = CLAMP(val, 0, 255);
169 }
170 } else if (in->color_spec == RGB) {
171 unsigned char *in_data = (unsigned char *) in->tiles[0].data;
172 unsigned char *out_data = (unsigned char *) out->tiles[0].data;
173
174 for (unsigned int i = 0; i < in->tiles[0].data_len; i += 3) {
175 double a[3];
176 a[0] = *in_data++;
177 a[1] = *in_data++;
178 a[2] = *in_data++;
179 int val = s->transform_matrix[0] * a[0] +
180 s->transform_matrix[1] * a[1] +
181 s->transform_matrix[2] * a[2];
182 *out_data++ = CLAMP(val, 0, 255);
183 val = s->transform_matrix[3] * a[0] +
184 s->transform_matrix[4] * a[1] +
185 s->transform_matrix[5] * a[2];
186 *out_data++ = CLAMP(val, 0, 255);
187 val = s->transform_matrix[6] * a[0] +
188 s->transform_matrix[7] * a[1] +
189 s->transform_matrix[8] * a[2];
190 *out_data++ = CLAMP(val, 0, 255);
191 }
192 } else if (in->color_spec == RG48) {
193 uint16_t *in_data = (uint16_t *)(void *) in->tiles[0].data;
194 uint16_t *out_data = (uint16_t *)(void *) out->tiles[0].data;
195
196 for (unsigned int i = 0; i < in->tiles[0].data_len; i += 6) {
197 double a[3];
198 a[0] = *in_data++;
199 a[1] = *in_data++;
200 a[2] = *in_data++;
201 int val = s->transform_matrix[0] * a[0] +
202 s->transform_matrix[1] * a[1] +
203 s->transform_matrix[2] * a[2];
204 *out_data++ = CLAMP(val, 0, 255);
205 val = s->transform_matrix[3] * a[0] +
206 s->transform_matrix[4] * a[1] +
207 s->transform_matrix[5] * a[2];
208 *out_data++ = CLAMP(val, 0, 255);
209 val = s->transform_matrix[6] * a[0] +
210 s->transform_matrix[7] * a[1] +
211 s->transform_matrix[8] * a[2];
212 *out_data++ = CLAMP(val, 0, 255);
213 }
214 } else {
215 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Only UYVY, RGB or RG48 is currently supported!\n");
217 vf_free(out);
218 return NULL;
219 }
220 } else {
221 if (in->color_spec == UYVY) {
222 unsigned char *in_data = (unsigned char *) in->tiles[0].data;
223 unsigned char *out_data = (unsigned char *) out->tiles[0].data;
224
225 for (unsigned int i = 0; i < in->tiles[0].data_len; i += 4) {
226 double a[3];
227 double b[3];
228 a[1] = b[1] = *in_data++;
229 a[0] = *in_data++;
230 a[2] = b[2] = *in_data++;
231 b[0] = *in_data++;
232 *out_data++ = s->transform_matrix[0] * (a[0] - 16) +
233 s->transform_matrix[1] * (a[1] - 128) +
234 s->transform_matrix[2] * (a[2] - 128);
235 *out_data++ = s->transform_matrix[3] * (a[0] - 16) +
236 s->transform_matrix[4] * (a[1] - 128) +
237 s->transform_matrix[5] * (a[2] - 128);
238 *out_data++ = s->transform_matrix[6] * (a[0] - 16) +
239 s->transform_matrix[7] * (a[1] - 128) +
240 s->transform_matrix[8] * (a[2] - 128);
241 *out_data++ = s->transform_matrix[0] * (b[0] - 16) +
242 s->transform_matrix[1] * (b[1] - 128) +
243 s->transform_matrix[2] * (b[2] - 128);
244 *out_data++ = s->transform_matrix[3] * (b[0] - 16) +
245 s->transform_matrix[4] * (b[1] - 128) +
246 s->transform_matrix[5] * (b[2] - 128);
247 *out_data++ = s->transform_matrix[6] * (b[0] - 16) +
248 s->transform_matrix[7] * (b[1] - 128) +
249 s->transform_matrix[8] * (b[2] - 128);
250 }
251 } else if (in->color_spec == RGB) {
252 unsigned char *in_data = (unsigned char *) in->tiles[0].data;
253 unsigned char *out_data = (unsigned char *) out->tiles[0].data;
254
255 for (unsigned int i = 0; i < in->tiles[0].data_len; i += 3) {
256 double a[3];
257 a[0] = *in_data++;
258 a[1] = *in_data++;
259 a[2] = *in_data++;
260 *out_data++ = s->transform_matrix[0] * a[0] +
261 s->transform_matrix[1] * a[1] +
262 s->transform_matrix[2] * a[2];
263 *out_data++ = s->transform_matrix[3] * a[0] +
264 s->transform_matrix[4] * a[1] +
265 s->transform_matrix[5] * a[2];
266 *out_data++ = s->transform_matrix[6] * a[0] +
267 s->transform_matrix[7] * a[1] +
268 s->transform_matrix[8] * a[2];
269 }
270 } else if (in->color_spec == RG48) {
271 uint16_t *in_data = (uint16_t *)(void *) in->tiles[0].data;
272 uint16_t *out_data = (uint16_t *)(void *) out->tiles[0].data;
273
274 for (unsigned int i = 0; i < in->tiles[0].data_len; i += 6) {
275 double a[3];
276 a[0] = *in_data++;
277 a[1] = *in_data++;
278 a[2] = *in_data++;
279 *out_data++ = s->transform_matrix[0] * a[0] +
280 s->transform_matrix[1] * a[1] +
281 s->transform_matrix[2] * a[2];
282 *out_data++ = s->transform_matrix[3] * a[0] +
283 s->transform_matrix[4] * a[1] +
284 s->transform_matrix[5] * a[2];
285 *out_data++ = s->transform_matrix[6] * a[0] +
286 s->transform_matrix[7] * a[1] +
287 s->transform_matrix[8] * a[2];
288 }
289 } else {
290 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Only UYVY, RGB or RG48 is currently supported!\n");
292 vf_free(out);
293 return NULL;
294 }
295 }
296
298
299 return out;
300}
301
302static void vo_pp_set_out_buffer(void *state, char *buffer)
303{
305 s->vo_pp_out_buffer = buffer;
306}
307
309 .init = init,
310 .done = done,
311 .filter = filter,
312};
313
315// coverity[leaked_storage:SUPPRESS]
317
318/* vim: set expandtab sw=8: */
#define UNUSED(x)
void ** state
int void * val
struct video_desc desc
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
void vf_data_deleter(struct video_frame *buf)
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
#define CAPTURE_FILTER_ABI_VERSION
#define ADD_VO_PP_CAPTURE_FILTER_WRAPPER(name, init, filter, done, set_out_buf, get_prop_callb)
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_RESET
Definition color_out.h:47
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
@ LIBRARY_CLASS_CAPTURE_FILTER
Definition lib_common.h:75
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define CLAMP(x, low, high)
Definition macros.h:67
static struct video_frame * filter(void *state, struct video_frame *in)
Definition matrix.c:117
static void vo_pp_set_out_buffer(void *state, char *buffer)
Definition matrix.c:302
static const struct capture_filter_info capture_filter_matrix
Definition matrix.c:308
#define MOD_NAME
Definition matrix.c:53
static void done(void *state)
Definition matrix.c:112
static int init(struct module *parent, const char *cfg, void **state)
Definition matrix.c:61
const char * parent
Definition settings.cpp:198
Definition hd-rum.c:27
void * vo_pp_out_buffer
buffer to write to if we use vo_pp wrapper (otherwise unused)
Definition matrix.c:58
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
codec_t color_spec
Definition types.h:182
void(* data_deleter)(struct video_frame *)
Definition types.h:256
void(* dispose)(struct video_frame *)
Definition types.h:245
Struct video_frame represents a video frame and contains video description.
Definition types.h:305
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
struct video_frame_callbacks callbacks
Definition types.h:324
codec_t color_spec
Definition types.h:306
@ 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
@ RG48
16-bit RGB little-endian (RlRhGl...)
Definition types.h:95
This is an umbrella header for video functions.
#define VIDEO_FRAME_DISPOSE(frame)
Definition video_frame.h:76