UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
matrix.c File Reference
#include "capture_filter.h"
#include "debug.h"
#include "lib_common.h"
#include "utils/color_out.h"
#include "utils/macros.h"
#include "video.h"
#include "video_codec.h"
#include "vo_postprocess/capture_filter_wrapper.h"
Include dependency graph for matrix.c:

Go to the source code of this file.

Classes

struct  state_capture_filter_matrix
 

Macros

#define MOD_NAME   "[matrix cap. f.] "
 

Functions

static void done (void *state)
 
static struct video_frame * filter (void *state, struct video_frame *in)
 
static int init (struct module *parent, const char *cfg, void **state)
 
 REGISTER_MODULE (matrix, &capture_filter_matrix, LIBRARY_CLASS_CAPTURE_FILTER, CAPTURE_FILTER_ABI_VERSION)
 
static void vo_pp_set_out_buffer (void *state, char *buffer)
 

Variables

static const struct capture_filter_info capture_filter_matrix
 

Detailed Description

Author
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z

Definition in file matrix.c.

Macro Definition Documentation

◆ MOD_NAME

#define MOD_NAME   "[matrix cap. f.] "

Definition at line 53 of file matrix.c.

Referenced by filter(), and init().

Function Documentation

◆ done()

static void done ( void * state)
static

Definition at line 112 of file matrix.c.

113{
114 free(state);
115}
void ** state

References state.

◆ filter()

static struct video_frame * filter ( void * state,
struct video_frame * in )
static

Definition at line 117 of file matrix.c.

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}
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.
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define CLAMP(x, low, high)
Definition macros.h:67
#define MOD_NAME
Definition matrix.c:53
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
#define VIDEO_FRAME_DISPOSE(frame)
Definition video_frame.h:76

References video_frame::callbacks, state_capture_filter_matrix::check_bounds, CLAMP, video_desc::color_spec, video_frame::color_spec, tile::data, video_frame_callbacks::data_deleter, tile::data_len, desc, video_frame_callbacks::dispose, LOG_LEVEL_ERROR, log_msg(), MOD_NAME, RG48, RGB, state, video_frame::tiles, state_capture_filter_matrix::transform_matrix, UYVY, val, vf_alloc_desc(), vf_data_deleter(), vf_free(), video_desc_from_frame(), VIDEO_FRAME_DISPOSE, and state_capture_filter_matrix::vo_pp_out_buffer.

Here is the call graph for this function:

◆ init()

static int init ( struct module * parent,
const char * cfg,
void ** state )
static

Definition at line 61 of file matrix.c.

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}
#define UNUSED(x)
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_RESET
Definition color_out.h:47
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
const char * parent
Definition settings.cpp:198
Definition hd-rum.c:27

References state_capture_filter_matrix::check_bounds, color_printf(), LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, log_msg(), MOD_NAME, parent, state, TERM_BOLD, TERM_RESET, state_capture_filter_matrix::transform_matrix, and UNUSED.

Here is the call graph for this function:

◆ REGISTER_MODULE()

REGISTER_MODULE ( matrix ,
& capture_filter_matrix,
LIBRARY_CLASS_CAPTURE_FILTER ,
CAPTURE_FILTER_ABI_VERSION  )

◆ vo_pp_set_out_buffer()

static void vo_pp_set_out_buffer ( void * state,
char * buffer )
static

Definition at line 302 of file matrix.c.

303{
305 s->vo_pp_out_buffer = buffer;
306}

References state, and state_capture_filter_matrix::vo_pp_out_buffer.

Variable Documentation

◆ capture_filter_matrix

const struct capture_filter_info capture_filter_matrix
static
Initial value:
= {
.init = init,
.done = done,
.filter = filter,
}
static struct video_frame * filter(void *state, struct video_frame *in)
Definition matrix.c:117
static void done(void *state)
Definition matrix.c:112
static int init(struct module *parent, const char *cfg, void **state)
Definition matrix.c:61

Definition at line 308 of file matrix.c.

308 {
309 .init = init,
310 .done = done,
311 .filter = filter,
312};