UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
aggregate.c
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
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#include "config_unix.h"
42#include "config_win32.h"
43#endif // HAVE_CONFIG_H
44
45#include "debug.h"
46#include "host.h"
47#include "lib_common.h"
48#include "tv.h"
49#include "video.h"
50#include "video_display.h"
51
52#include <assert.h>
53#include <host.h>
54
55#define MAGIC_AGGREGATE 0xbbcaa321
56
58 pthread_t thread_id;
59 struct display **devices;
60 unsigned int devices_cnt;
63 struct tile *tile;
64
65 /* For debugging... */
66 uint32_t magic;
67
68 int frames;
69 struct timeval t, t0;
70};
71
72static void show_help(void);
73static void show_help() {
74 printf("Aggregate display\n");
75 printf("Usage:\n");
76 printf("\t-t aggregate:<dev1_config>#<dev2_config>[#....]\n");
77 printf("\t\twhere devn_config is a complete configuration string of device involved in an aggregate device\n");
78}
79
80static void *display_aggregate_run(void *state)
81{
83 unsigned int i;
84
85 for (i = 0; i < s->devices_cnt; i++) {
87 }
88 for (i = 0; i < s->devices_cnt; i++) {
89 display_join(s->devices[i]);
90 }
91 return NULL;
92}
93
94static void display_aggregate_probe(struct device_info **available_cards, int *count, void (**deleter)(void *))
95{
97 *available_cards = NULL;
98 *count = 0;
99}
100
101static void *display_aggregate_init(struct module *parent, const char *fmt, unsigned int flags)
102{
103 UNUSED(parent);
104 struct display_aggregate_state *s;
105 char *save_ptr = NULL;
106 char *item;
107 char *parse_string = NULL;;
108 char *tmp;
109 int i;
110
111 if(!fmt || strcmp(fmt, "help") == 0) {
112 show_help();
113 return INIT_NOERR;
114 }
115
116 s = (struct display_aggregate_state *) calloc(1, sizeof(struct display_aggregate_state));
118
119 s->devices_cnt = 0;
120 tmp = parse_string = strdup(fmt);
121 assert(tmp != NULL);
122 while(strtok_r(tmp, "#", &save_ptr)) {
123 s->devices_cnt++;
124 tmp = NULL;
125 }
126 free(parse_string);
127
128 s->devices = calloc(1, s->devices_cnt * sizeof(struct display *));
129 i = 0;
130 tmp = parse_string = strdup(fmt);
131 while((item = strtok_r(tmp, "#", &save_ptr))) {
132 char *device;
133 char *config = strdup(item);
134 const char *device_cfg = "";
135 unsigned int dev_flags = 0u;
136 device = config;
137 if(strchr(config, ':')) {
138 char *delim = strchr(config, ':');
139 *delim = '\0';
140 device_cfg = delim + 1;
141 }
142 if(i == 0) {
143 dev_flags = flags;
144 } else { // push audio only to first device
146 }
147
148 int ret = initialize_video_display(parent, device,
149 device_cfg, dev_flags, NULL, &s->devices[i]);
150 if(ret != 0) {
151 fprintf(stderr, "[aggregate] Unable to initialize device %d (%s:%s).\n", i, device, device_cfg);
152 free(config);
153 goto error;
154 }
155 free(config);
156 ++i;
157 tmp = NULL;
158 }
159 free(parse_string);
160
161 s->frame = vf_alloc(s->devices_cnt);
162 s->dev_frames = calloc(s->devices_cnt, sizeof(struct video_frame *));
163
164 pthread_create(&s->thread_id, NULL, display_aggregate_run, s);
165 return (void *)s;
166
167error:
168 free(parse_string);
169 if(s->devices) {
170 unsigned int i;
171 for (i = 0u; i < s->devices_cnt; ++i) {
172 if(s->devices[i]) {
173 display_done(s->devices[i]);
174 }
175 }
176 }
177 free(s);
178 return NULL;
179}
180
182{
184
185 assert(s != NULL);
186 assert(s->magic == MAGIC_AGGREGATE);
187
188 pthread_join(s->thread_id, NULL);
189
190 for (unsigned int i = 0; i < s->devices_cnt; ++i) {
191 display_done(s->devices[i]);
192 }
193
194 vf_free(s->frame);
195 free(s->dev_frames);
196 free(s);
197}
198
200{
202 unsigned int i;
203 struct video_frame *frame;
204
205 assert(s != NULL);
206 assert(s->magic == MAGIC_AGGREGATE);
207
208
209 for(i = 0; i < s->devices_cnt; ++i) {
211 s->dev_frames[i] = frame;
212 vf_get_tile(s->frame, i)->data = frame->tiles[0].data;
214 }
215
216 return s->frame;
217}
218
219static bool display_aggregate_putf(void *state, struct video_frame *frame, long long nonblock)
220{
221 unsigned int i;
223
224 assert(s->magic == MAGIC_AGGREGATE);
225 for(i = 0; i < s->devices_cnt; ++i) {
226 struct video_frame *dev_frame = NULL;
227 if(frame)
228 dev_frame = s->dev_frames[i];
229 bool ret = display_put_frame(s->devices[i], dev_frame, nonblock);
230 if (!ret) {
231 return ret;
232 }
233 }
234
235 return true;
236}
237
239{
241 unsigned int i;
242 bool ret = false;
243
244 assert(s->magic == MAGIC_AGGREGATE);
245
246 s->frame->fps = desc.fps;
249
250 desc.tile_count = 1;
251 for(i = 0; i < s->devices_cnt; ++i) {
253 if(!ret)
254 break;
255 }
256
257 return ret;
258}
259
260static bool display_aggregate_get_property(void *state, int property, void *val, size_t *len)
261{
263 unsigned int i;
264
265 switch (property) {
267 {
268 unsigned int codec_idx;
269 unsigned int save_codec_idx = 0;
270 codec_t **codecs = malloc(s->devices_cnt * sizeof(codec_t *));
271 size_t *lens = malloc(s->devices_cnt * sizeof(size_t));
272
273 assert(s->devices_cnt > 0);
274 for (i = 0; i < s->devices_cnt; ++i) {
275 codecs[i] = malloc(*len);
276 lens[i] = *len;
277 }
278 for (i = 0; i < s->devices_cnt; ++i) {
279 int ret;
281 if(!ret) {
282 goto err_codecs;
283 }
284 }
285
286 /* for each codec check if is included in all drivers */
287 for(codec_idx = 0; codec_idx < lens[0] / sizeof(codec_t); codec_idx++) {
288 unsigned int found = 0;
289 codec_t examined = codecs[0][codec_idx];
290 for (i = 1; i < s->devices_cnt; ++i) {
291 unsigned int sub_codec;
292 for(sub_codec = 0; sub_codec < lens[i] / sizeof(codec_t); ++sub_codec) {
293 if(examined == codecs[i][sub_codec]) {
294 ++found;
295 }
296 }
297 }
298
299 /* is included in all drivers */
300 if(found == s->devices_cnt - 1) {
301 ((codec_t *) val)[save_codec_idx++] = examined;
302 }
303 }
304
305 *len = save_codec_idx * sizeof(codec_t);
306 for(i = 0; i < s->devices_cnt; ++i) {
307 free(codecs[i]);
308 }
309 free(codecs);
310 free(lens);
311 return true;
312err_codecs:
313 for(i = 0; i < s->devices_cnt; ++i) {
314 free(codecs[i]);
315 }
316 free(codecs);
317 free(lens);
318 return false;
319 }
320 break;
323 {
324 int ret;
325 char first_val[128];
326 size_t first_size = sizeof(first_val);
327 ret = display_ctl_property(s->devices[0], property, &first_val, &first_size);
328 if(!ret) goto err;
329
330 for (i = 1; i < s->devices_cnt; ++i) {
331 char new_val[128];
332 size_t new_size = sizeof(new_val);
333 ret = display_ctl_property(s->devices[i], property, &new_val, &new_size);
334 if(!ret) goto err;
335 if(new_size != first_size || memcmp(first_val, new_val, first_size) != 0)
336 goto err;
337
338 }
339 if (first_size > *len)
340 goto err;
341 *len = first_size;
342 memcpy(val, first_val, first_size);
343 return true;
344err:
345 return false;
346
347 }
349 if(s->devices_cnt == 1)
351 else
353 break;
354
355 default:
356 return false;
357 }
358 return true;
359}
360
362{
364 double seconds = tv_diff(s->t, s->t0);
365
366 if (seconds >= 5) {
367 float fps = s->frames / seconds;
368 log_msg(LOG_LEVEL_INFO, "[aggregate disp.] %d frames in %g seconds = %g FPS\n", s->frames, seconds, fps);
369 s->t0 = s->t;
370 s->frames = 0;
371 }
372
374}
375
382
396
398
#define UNUSED(x)
void ** state
struct video_frame long long nonblock
int void * val
struct video_desc desc
int int int sample_rate
int int channels
struct video_frame * frame
const char * fmt
int void size_t * len
const char unsigned int flags
int void(** deleter)(void *))
int property
int quant_samples
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
void vf_free(struct video_frame *buf)
Frees video_frame structure.
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62
bool display_reconfigure_audio(struct display *d, int quant_samples, int channels, int sample_rate)
void display_put_audio_frame(struct display *d, const struct audio_frame *frame)
Puts audio data.
bool display_put_frame(struct display *d, struct video_frame *frame, long long timeout_ns)
Puts filled video frame. After calling this function, video frame cannot be used.
#define DISPLAY_FLAG_AUDIO_ANALOG
bool display_ctl_property(struct display *d, int property, void *val, size_t *len)
Gets property from video display.
void display_run_new_thread(struct display *d)
#define DISPLAY_FLAG_AUDIO_AESEBU
#define VIDEO_DISPLAY_ABI_VERSION
#define DISPLAY_NO_GENERIC_FPS_INDICATOR
#define DISPLAY_FLAG_AUDIO_EMBEDDED
void display_done(struct display *d)
This function performs cleanup after done.
void display_join(struct display *d)
int initialize_video_display(struct module *parent, const char *requested_display, const char *fmt, unsigned int flags, const char *postprocess, struct display **out)
Initializes video display.
struct video_frame * display_get_frame(struct display *d)
Returns video framebuffer which will be written to.
@ DISPLAY_PROPERTY_BUF_PITCH
requested framebuffer pitch - int (bytes), may be PITCH_DEFAULT
@ DISPLAY_PROPERTY_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_VIDEO_MODE
requested video mode - int (one of display_prop_vid_mode)
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
@ DISPLAY_PROPERTY_VIDEO_SEPARATE_TILES
framebuffer consists of separate tiles
@ DISPLAY_PROPERTY_VIDEO_MERGED
monolithic framebuffer
int count
Definition hd-rum.c:44
#define INIT_NOERR
Definition host.h:73
@ LIBRARY_CLASS_VIDEO_DISPLAY
Definition lib_common.h:79
#define REGISTER_HIDDEN_MODULE(name, info, lclass, abi)
Definition lib_common.h:156
const char * parent
Definition settings.cpp:198
struct used to comunicate with audio capture/playback device
Definition types.h:99
struct video_frame ** dev_frames
Definition aggregate.c:62
struct tile * tile
Definition aggregate.c:63
struct display ** devices
Definition aggregate.c:59
unsigned int devices_cnt
Definition aggregate.c:60
struct video_frame * frame
Definition aggregate.c:61
struct timeval t t0
Definition aggregate.c:69
This struct represents initialized video display state.
Definition hd-rum.c:27
Struct tile is an area of video_frame.
Definition types.h:279
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
unsigned int tile_count
Definition types.h:185
codec_t color_spec
Definition types.h:182
enum interlacing_t interlacing
Definition types.h:184
double fps
Definition types.h:183
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
double fps
Definition types.h:308
codec_t color_spec
Definition types.h:306
double tv_diff(struct timeval curr_time, struct timeval prev_time)
Definition tv.c:97
@ VIDEO_NORMAL
normal video (one tile)
Definition types.h:356
codec_t
Definition types.h:65
This is an umbrella header for video functions.
static void show_help(void)
Definition aggregate.c:60
static struct @76 codecs[]
static bool display_aggregate_putf(void *state, struct video_frame *frame, long long nonblock)
Definition aggregate.c:219
static void * display_aggregate_init(struct module *parent, const char *fmt, unsigned int flags)
Definition aggregate.c:101
static const struct video_display_info display_aggregate_info
Definition aggregate.c:383
static bool display_aggregate_get_property(void *state, int property, void *val, size_t *len)
Definition aggregate.c:260
static void display_aggregate_put_audio_frame(void *state, const struct audio_frame *frame)
Definition aggregate.c:361
static struct video_frame * display_aggregate_getf(void *state)
Definition aggregate.c:199
#define MAGIC_AGGREGATE
Definition aggregate.c:55
static void display_aggregate_done(void *state)
Definition aggregate.c:181
static bool display_aggregate_reconfigure(void *state, struct video_desc desc)
Definition aggregate.c:238
static void * display_aggregate_run(void *state)
Definition aggregate.c:80
static void display_aggregate_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
Definition aggregate.c:94
static bool display_aggregate_reconfigure_audio(void *state, int quant_samples, int channels, int sample_rate)
Definition aggregate.c:376
bool display_reconfigure(struct display *d, struct video_desc desc, enum video_mode video_mode)
Reconfigure display to new video format.
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].