UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
blend.cpp File Reference
#include "config.h"
#include "config_unix.h"
#include "config_win32.h"
#include "debug.h"
#include "lib_common.h"
#include "video.h"
#include "video_display.h"
#include <cinttypes>
#include <condition_variable>
#include <chrono>
#include <iostream>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <queue>
#include <thread>
#include <unordered_map>
Include dependency graph for blend.cpp:

Go to the source code of this file.

Classes

struct  state_blend
 
struct  state_blend_common
 

Functions

static void check_reconf (struct state_blend_common *s, struct video_desc desc)
 
static void display_blend_done (void *state)
 
static struct display * display_blend_fork (void *state)
 
static bool display_blend_get_property (void *state, int property, void *val, size_t *len)
 
static struct video_frame * display_blend_getf (void *state)
 
static void * display_blend_init (struct module *parent, const char *fmt, unsigned int flags)
 
static void display_blend_probe (struct device_info **available_cards, int *count, void(**deleter)(void *))
 
static void display_blend_put_audio_frame (void *state, const struct audio_frame *frame)
 
static bool display_blend_putf (void *state, struct video_frame *frame, long long flags)
 
static bool display_blend_reconfigure (void *state, struct video_desc desc)
 
static bool display_blend_reconfigure_audio (void *state, int quant_samples, int channels, int sample_rate)
 
static void display_blend_run (void *state)
 
 REGISTER_HIDDEN_MODULE (blend, &display_blend_info, LIBRARY_CLASS_VIDEO_DISPLAY, VIDEO_DISPLAY_ABI_VERSION)
 
static constexpr chrono::milliseconds SOURCE_TIMEOUT (500)
 

Variables

static constexpr int BUFFER_LEN = 5
 
static const struct video_display_info display_blend_info
 
static constexpr unsigned int IN_QUEUE_MAX_BUFFER_LEN = 5
 
static constexpr int SKIP_FIRST_N_FRAMES_IN_STREAM = 5
 
static constexpr int TRANSITION_COUNT = 10
 

Detailed Description

Author
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z
Todo
Rewrite the code to have more clear state machine!

Definition in file blend.cpp.

Function Documentation

◆ check_reconf()

static void check_reconf ( struct state_blend_common * s,
struct video_desc desc )
static

Definition at line 164 of file blend.cpp.

165{
166 if (!video_desc_eq(desc, s->display_desc)) {
167 s->display_desc = desc;
168 fprintf(stderr, "RECONFIGURED\n");
170 }
171}
struct video_desc desc
struct display * real_display
Definition blend.cpp:84
struct video_desc display_desc
Definition blend.cpp:85
@ VIDEO_NORMAL
normal video (one tile)
Definition types.h:356
bool display_reconfigure(struct display *d, struct video_desc desc, enum video_mode video_mode)
Reconfigure display to new video format.
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.

References desc, state_blend_common::display_desc, display_reconfigure(), state_blend_common::real_display, video_desc_eq(), and VIDEO_NORMAL.

Referenced by display_blend_run(), and display_conference_worker().

Here is the call graph for this function:

◆ display_blend_done()

static void display_blend_done ( void * state)
static

Definition at line 332 of file blend.cpp.

333{
334 struct state_blend *s = (struct state_blend *)state;
335 delete s;
336}
void ** state

References state.

◆ display_blend_fork()

static struct display * display_blend_fork ( void * state)
static

Definition at line 109 of file blend.cpp.

110{
111 shared_ptr<struct state_blend_common> s = ((struct state_blend *)state)->common;
112 struct display *out;
113 char fmt[2 + sizeof(void *) * 2 + 1] = "";
114 snprintf(fmt, sizeof fmt, "%p", state);
115
116 int rc = initialize_video_display(s->parent,
117 "blend", fmt, 0, NULL, &out);
118 if (rc == 0) return out; else return NULL;
119
120 return out;
121}
const char * fmt
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.
This struct represents initialized video display state.
shared_ptr< struct state_blend_common > common
Definition blend.cpp:105

References state_blend::common, fmt, initialize_video_display(), and state.

Referenced by display_blend_get_property().

Here is the call graph for this function:

◆ display_blend_get_property()

static bool display_blend_get_property ( void * state,
int property,
void * val,
size_t * len )
static

Definition at line 369 of file blend.cpp.

370{
371 shared_ptr<struct state_blend_common> s = ((struct state_blend *)state)->common;
373 ((struct multi_sources_supp_info *) val)->val = true;
375 ((struct multi_sources_supp_info *) val)->state = state;
376 *len = sizeof(struct multi_sources_supp_info);
377 return true;
378 }
379 return display_ctl_property(s->real_display, property, val, len);
380}
int void * val
int void size_t * len
int property
static struct display * display_blend_fork(void *state)
Definition blend.cpp:109
bool display_ctl_property(struct display *d, int property, void *val, size_t *len)
Gets property from video display.
@ DISPLAY_PROPERTY_SUPPORTS_MULTI_SOURCES
struct display *(* fork_display)(void *state)

References state_blend::common, display_blend_fork(), display_ctl_property(), DISPLAY_PROPERTY_SUPPORTS_MULTI_SOURCES, multi_sources_supp_info::fork_display, len, property, state, and val.

Here is the call graph for this function:

◆ display_blend_getf()

static struct video_frame * display_blend_getf ( void * state)
static

Definition at line 338 of file blend.cpp.

339{
340 struct state_blend *s = (struct state_blend *)state;
341
342 return vf_alloc_desc_data(s->desc);
343}
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
struct video_desc desc
Definition blend.cpp:106

References state_blend::desc, state, and vf_alloc_desc_data().

Here is the call graph for this function:

◆ display_blend_init()

static void * display_blend_init ( struct module * parent,
const char * fmt,
unsigned int flags )
static

Definition at line 123 of file blend.cpp.

124{
125 char *fmt_copy = NULL;
126 const char *requested_display = "";
127 const char *cfg = "";
128 int ret;
129
130 if (fmt == nullptr || strlen(fmt) == 0 || "help"s == fmt) {
131 cout << "blend is a helper display to combine (blend) multiple incoming streams.\n"
132 "Please do not use directly, intended for internal purposes!\n";
133 return nullptr;
134 }
135
136 auto *s = new state_blend();
137
138 if (isdigit(fmt[0]) != 0) { // fork
139 struct state_blend *orig = nullptr;
140 sscanf(fmt, "%p", &orig);
141 s->common = orig->common;
142 return s;
143 }
144 fmt_copy = strdup(fmt);
145 requested_display = fmt_copy;
146 char *delim = strchr(fmt_copy, ':');
147 if (delim != nullptr) {
148 *delim = '\0';
149 cfg = delim + 1;
150 }
151 s->common = shared_ptr<state_blend_common>(new state_blend_common());
152 ret = initialize_video_display(parent, requested_display, cfg, flags, NULL, &s->common->real_display);
153 assert(ret == 0 && "Unable to initialize real display for blend");
154 free(fmt_copy);
155
156 display_run_new_thread(s->common->real_display);
157
158 s->common->parent = parent;
159 s->common->thread_id = thread(display_blend_run, s);
160
161 return s;
162}
const char unsigned int flags
static void display_blend_run(void *state)
Definition blend.cpp:173
void display_run_new_thread(struct display *d)
const char * parent
Definition settings.cpp:198

References state_blend::common, display_blend_run(), display_run_new_thread(), flags, fmt, initialize_video_display(), and parent.

Here is the call graph for this function:

◆ display_blend_probe()

static void display_blend_probe ( struct device_info ** available_cards,
int * count,
void(** deleter )(void *) )
static

Definition at line 408 of file blend.cpp.

408 {
410 *available_cards = nullptr;
411 *count = 0;
412}
#define UNUSED(x)
int void(** deleter)(void *))
int count
Definition hd-rum.c:44

References count, deleter, and UNUSED.

◆ display_blend_put_audio_frame()

static void display_blend_put_audio_frame ( void * state,
const struct audio_frame * frame )
static

Definition at line 391 of file blend.cpp.

392{
393 UNUSED(state);
394 UNUSED(frame);
395}
struct video_frame * frame

References frame, state, and UNUSED.

◆ display_blend_putf()

static bool display_blend_putf ( void * state,
struct video_frame * frame,
long long flags )
static

Definition at line 345 of file blend.cpp.

346{
347 shared_ptr<struct state_blend_common> s = ((struct state_blend *)state)->common;
348
349 if (flags == PUTF_DISCARD) {
350 vf_free(frame);
351 } else {
352 unique_lock<mutex> lg(s->lock);
353 if (s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN) {
354 fprintf(stderr, "blend: queue full!\n");
355 }
356 if (flags != PUTF_BLOCKING && s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN) {
357 vf_free(frame);
358 return 1;
359 }
360 s->in_queue_decremented_cv.wait(lg, [s]{return s->incoming_queue.size() < IN_QUEUE_MAX_BUFFER_LEN;});
361 s->incoming_queue.push(frame);
362 lg.unlock();
363 s->cv.notify_one();
364 }
365
366 return true;
367}
void vf_free(struct video_frame *buf)
Frees video_frame structure.
static constexpr unsigned int IN_QUEUE_MAX_BUFFER_LEN
Definition blend.cpp:68
#define PUTF_DISCARD
#define PUTF_BLOCKING

References state_blend::common, flags, frame, IN_QUEUE_MAX_BUFFER_LEN, PUTF_BLOCKING, PUTF_DISCARD, state, and vf_free().

Here is the call graph for this function:

◆ display_blend_reconfigure()

static bool display_blend_reconfigure ( void * state,
struct video_desc desc )
static

Definition at line 382 of file blend.cpp.

383{
384 struct state_blend *s = (struct state_blend *) state;
385
386 s->desc = desc;
387
388 return true;
389}

References desc, state_blend::desc, and state.

◆ display_blend_reconfigure_audio()

static bool display_blend_reconfigure_audio ( void * state,
int quant_samples,
int channels,
int sample_rate )
static

Definition at line 397 of file blend.cpp.

399{
400 UNUSED(state);
404
405 return false;
406}
int int int sample_rate
int int channels
int quant_samples

References channels, quant_samples, sample_rate, state, and UNUSED.

◆ display_blend_run()

static void display_blend_run ( void * state)
static

Definition at line 173 of file blend.cpp.

174{
175 shared_ptr<struct state_blend_common> s = ((struct state_blend *)state)->common;
176 bool prefill = false;
177 int skipped = 0;
178
179 while (1) {
180 struct video_frame *frame;
181 {
182 unique_lock<mutex> lg(s->lock);
183 s->cv.wait(lg, [s]{return s->incoming_queue.size() > 0;});
184 frame = s->incoming_queue.front();
185 s->incoming_queue.pop();
186 s->in_queue_decremented_cv.notify_one();
187 }
188
189 if (!frame) {
190 display_put_frame(s->real_display, NULL, PUTF_BLOCKING);
191 break;
192 }
193
194 chrono::system_clock::time_point now = chrono::system_clock::now();
195 auto it = s->disabled_ssrc.find(frame->ssrc);
196 if (it != s->disabled_ssrc.end()) {
197 it->second = now;
198 vf_free(frame);
199 continue;
200 }
201
202 it = s->disabled_ssrc.begin();
203 while (it != s->disabled_ssrc.end()) {
204 if (chrono::duration_cast<chrono::milliseconds>(now - it->second) > SOURCE_TIMEOUT) {
205 verbose_msg("Source 0x%08" PRIx32 " timeout. Deleting from blend display.\n", it->first);
206 s->disabled_ssrc.erase(it++);
207 } else {
208 ++it;
209 }
210 }
211
212 if (frame->ssrc != s->current_ssrc && frame->ssrc != s->old_ssrc) {
213 if (skipped >= SKIP_FIRST_N_FRAMES_IN_STREAM) {
214 s->old_ssrc = s->current_ssrc; // if != 0, we will be in transition state
215 s->current_ssrc = frame->ssrc;
216 prefill = true;
217 skipped = 0;
218 } else {
219 skipped++;
220 continue;
221 }
222 }
223
224 s->frames[frame->ssrc].push_back(frame);
225
226 if (s->frames[s->current_ssrc].size() >= BUFFER_LEN) {
227 prefill = false;
228 }
229
230 // we may receive two streams concurrently, therefore we use the timing according to
231 // the later one
232 if (frame->ssrc != s->current_ssrc) {
233 continue;
234 }
235
236 if (s->old_ssrc != 0) {
237 if (prefill) {
238 auto & ssrc_list = s->frames[s->old_ssrc];
239 if (ssrc_list.empty()) {
240 fprintf(stderr, "SMOLIK1!\n");
241 } else {
242 frame = ssrc_list.front();
243 ssrc_list.pop_front();
244
246
247 struct video_frame *real_display_frame = display_get_frame(s->real_display);
248 memcpy(real_display_frame->tiles[0].data, frame->tiles[0].data, frame->tiles[0].data_len);
249 vf_free(frame);
250 real_display_frame->ssrc = s->current_ssrc;
251 display_put_frame(s->real_display, real_display_frame, PUTF_BLOCKING);
252 }
253 } else {
254 auto & old_list = s->frames[s->old_ssrc];
255 auto & new_list = s->frames[s->current_ssrc];
256
257 s->transition += 1;
258
259 if (old_list.empty() || new_list.empty()) {
260 fprintf(stderr, "SMOLIK2!\n");
261 // ok here, we do not have nothing to mix, therefore cancel smooth transition
262 s->transition = TRANSITION_COUNT;
263 } else {
264 struct video_frame *old_frame, *new_frame;
265
266 old_frame = old_list.front();
267 old_list.pop_front();
268 new_frame = new_list.front();
269 new_list.pop_front();
270
271 struct video_desc old_desc = video_desc_from_frame(old_frame),
272 new_desc = video_desc_from_frame(new_frame);
273
274 check_reconf(s.get(), new_desc);
275
276 struct video_frame *real_display_frame = display_get_frame(s->real_display);
277
278 if (video_desc_eq(old_desc, new_desc)) {
279 for (unsigned int i = 0; i < new_frame->tiles[0].data_len; ++i) {
280 int old_val = ((unsigned char *) old_frame->tiles[0].data)[i];
281 int new_val = ((unsigned char *) new_frame->tiles[0].data)[i];
282 ((unsigned char *) real_display_frame->tiles[0].data)[i] =
283 ((new_val * s->transition) + (old_val * (TRANSITION_COUNT - s->transition))) / TRANSITION_COUNT;
284 }
285 } else {
286 // new desc is different than old desc!
287 fprintf(stderr, "SMOLIK4!\n");
288 memcpy(real_display_frame->tiles[0].data, new_frame->tiles[0].data, new_frame->tiles[0].data_len);
289 }
290 vf_free(old_frame);
291 vf_free(new_frame);
292 real_display_frame->ssrc = s->current_ssrc;
293 display_put_frame(s->real_display, real_display_frame, PUTF_BLOCKING);
294 }
295 }
296 } else {
297 if (!prefill) {
298 if (s->frames[s->current_ssrc].empty()) {
299 // this should not happen, heh ?
300 fprintf(stderr, "SMOLIK3!\n");
301 } else {
302 frame = s->frames[s->current_ssrc].front();
303 s->frames[s->current_ssrc].pop_front();
304
306
307 struct video_frame *real_display_frame = display_get_frame(s->real_display);
308 memcpy(real_display_frame->tiles[0].data, frame->tiles[0].data, frame->tiles[0].data_len);
309 vf_free(frame);
310 real_display_frame->ssrc = s->current_ssrc;
311 display_put_frame(s->real_display, real_display_frame, PUTF_BLOCKING);
312 }
313 }
314 }
315
316 if (s->old_ssrc != 0 && s->transition >= TRANSITION_COUNT) {
317 for (auto && frame : s->frames[s->old_ssrc]) {
318 vf_free(frame);
319 }
320
321 s->frames.erase(s->old_ssrc);
322
323 s->disabled_ssrc[s->old_ssrc] = chrono::system_clock::now();
324 s->old_ssrc = 0u;
325 s->transition = 0;
326 }
327 }
328
329 display_join(s->real_display);
330}
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
static constexpr int BUFFER_LEN
Definition blend.cpp:66
static constexpr chrono::milliseconds SOURCE_TIMEOUT(500)
static void check_reconf(struct state_blend_common *s, struct video_desc desc)
Definition blend.cpp:164
static constexpr int TRANSITION_COUNT
Definition blend.cpp:65
static constexpr int SKIP_FIRST_N_FRAMES_IN_STREAM
Definition blend.cpp:69
#define verbose_msg(...)
Definition debug.h:90
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.
void display_join(struct display *d)
struct video_frame * display_get_frame(struct display *d)
Returns video framebuffer which will be written to.
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
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
uint32_t ssrc
Definition types.h:330

References BUFFER_LEN, check_reconf(), state_blend::common, tile::data, tile::data_len, display_get_frame(), display_join(), display_put_frame(), frame, PUTF_BLOCKING, SKIP_FIRST_N_FRAMES_IN_STREAM, SOURCE_TIMEOUT(), video_frame::ssrc, state, video_frame::tiles, TRANSITION_COUNT, verbose_msg, vf_free(), video_desc_eq(), and video_desc_from_frame().

Referenced by display_blend_init().

Here is the call graph for this function:

◆ REGISTER_HIDDEN_MODULE()

REGISTER_HIDDEN_MODULE ( blend ,
& display_blend_info,
LIBRARY_CLASS_VIDEO_DISPLAY ,
VIDEO_DISPLAY_ABI_VERSION  )

◆ SOURCE_TIMEOUT()

static constexpr chrono::milliseconds SOURCE_TIMEOUT ( 500 )
staticconstexpr

Referenced by display_blend_run().

Variable Documentation

◆ BUFFER_LEN

int BUFFER_LEN = 5
staticconstexpr

Definition at line 66 of file blend.cpp.

Referenced by display_blend_run().

◆ display_blend_info

const struct video_display_info display_blend_info
static
Initial value:
= {
NULL,
}
static bool display_blend_get_property(void *state, int property, void *val, size_t *len)
Definition blend.cpp:369
static void display_blend_done(void *state)
Definition blend.cpp:332
static bool display_blend_putf(void *state, struct video_frame *frame, long long flags)
Definition blend.cpp:345
static void display_blend_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
Definition blend.cpp:408
static bool display_blend_reconfigure(void *state, struct video_desc desc)
Definition blend.cpp:382
static bool display_blend_reconfigure_audio(void *state, int quant_samples, int channels, int sample_rate)
Definition blend.cpp:397
static void display_blend_put_audio_frame(void *state, const struct audio_frame *frame)
Definition blend.cpp:391
static void * display_blend_init(struct module *parent, const char *fmt, unsigned int flags)
Definition blend.cpp:123
static struct video_frame * display_blend_getf(void *state)
Definition blend.cpp:338
#define DISPLAY_NO_GENERIC_FPS_INDICATOR

Definition at line 414 of file blend.cpp.

◆ IN_QUEUE_MAX_BUFFER_LEN

unsigned int IN_QUEUE_MAX_BUFFER_LEN = 5
staticconstexpr

Definition at line 68 of file blend.cpp.

Referenced by display_blend_putf(), and display_conference_putf().

◆ SKIP_FIRST_N_FRAMES_IN_STREAM

int SKIP_FIRST_N_FRAMES_IN_STREAM = 5
staticconstexpr

Definition at line 69 of file blend.cpp.

Referenced by display_blend_run().

◆ TRANSITION_COUNT

int TRANSITION_COUNT = 10
staticconstexpr

Definition at line 65 of file blend.cpp.

Referenced by display_blend_run().