UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
multiplier.cpp
Go to the documentation of this file.
1
6/*
7 * Copyright (c) 2014-2024 CESNET, z. s. p. o.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, is permitted provided that the following conditions
12 * are met:
13 *
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 *
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * 3. Neither the name of CESNET nor the names of its contributors may be
22 * used to endorse or promote products derived from this software without
23 * specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
27 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
29 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
35 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include "config.h"
40#include "config_unix.h"
41#include "config_win32.h"
42#include "debug.h"
43#include "host.h"
44#include "lib_common.h"
45#include "video.h"
46#include "video_display.h"
48
49#include <condition_variable>
50#include <vector>
51#include <memory>
52#include <mutex>
53#include <queue>
54#include <thread>
55
56using namespace std;
57
58static constexpr unsigned int IN_QUEUE_MAX_BUFFER_LEN = 5;
59static constexpr const char *MOD_NAME = "[multiplier] ";
60static constexpr int SKIP_FIRST_N_FRAMES_IN_STREAM = 5;
61
62namespace{
63struct disp_deleter{ void operator()(display *d){ display_done(d); } };
64using unique_disp = std::unique_ptr<struct display, disp_deleter>;
65}
66
68 std::vector<unique_disp> displays;
69
71
72 queue<struct video_frame *> incoming_queue;
73 condition_variable in_queue_decremented_cv;
74
75 mutex lock;
76 condition_variable cv;
77
78 struct module *parent;
80};
81
82static void show_help(){
83 printf("Multiplier display\n");
84 printf("Usage:\n");
85 printf("\t-d multiplier:<display1>[:<display_config1>][#<display2>[:<display_config2>]]...\n");
86}
87
88static void *display_multiplier_init(struct module *parent, const char *fmt, unsigned int flags)
89{
90 auto s = std::make_unique<state_multiplier>();
91
92 if(!fmt || strlen(fmt) == 0){
93 show_help();
94 return INIT_NOERR;
95 }
96
97 std::string_view fmt_sv = fmt;
98
99 if (fmt_sv == "help") {
100 show_help();
101 return INIT_NOERR;
102 }
103
104 s->parent = parent;
105
106 for(auto tok = tokenize(fmt_sv, '#'); !tok.empty(); tok = tokenize(fmt_sv, '#')){
107 LOG(LOG_LEVEL_VERBOSE) << MOD_NAME << "Initializing display " << tok << "\n";
108 auto display = std::string(tokenize(tok, ':'));
109 auto cfg = std::string(tok);
110
111 struct display *d_ptr;
112 if (initialize_video_display(parent, display.c_str(), cfg.c_str(), flags, NULL, &d_ptr) != 0) {
113 LOG(LOG_LEVEL_FATAL) << "[multiplier] Unable to initialize a display " << display << "!\n";
114 return nullptr;
115 }
116 unique_disp disp(d_ptr);
117 if (display_needs_mainloop(disp.get()) && !s->displays.empty()) {
118 LOG(LOG_LEVEL_ERROR) << "[multiplier] Display " << display << " needs mainloop and should be given first!\n";
119 }
120
121 s->displays.push_back(std::move(disp));
122 }
123
124 return s.release();
125}
126
127static void check_reconf(struct state_multiplier *s, struct video_desc *current_desc,
128 struct video_desc desc)
129{
130 if (video_desc_eq(desc, *current_desc)) {
131 return;
132 }
133 *current_desc = desc;
134 fprintf(stderr, "RECONFIGURED\n");
135 for (auto &disp : s->displays) {
137 }
138}
139
141{
142 auto *s = (struct state_multiplier *)state;
143 int skipped = 0;
144 struct video_desc display_desc{};
145
146 while (1) {
147 struct video_frame *frame;
148 {
149 unique_lock<mutex> lg(s->lock);
150 s->cv.wait(lg, [s]{return s->incoming_queue.size() > 0;});
151 frame = s->incoming_queue.front();
152 s->incoming_queue.pop();
153 s->in_queue_decremented_cv.notify_one();
154 }
155
156 if (!frame) {
157 for (auto& disp : s->displays) {
158 display_put_frame(disp.get(), NULL, PUTF_BLOCKING);
159 }
160 break;
161 }
162
163 if (skipped < SKIP_FIRST_N_FRAMES_IN_STREAM){
164 skipped++;
165 vf_free(frame);
166 continue;
167 }
168
169 check_reconf(s, &display_desc, video_desc_from_frame(frame));
170
171 for (auto& disp : s->displays) {
172 struct video_frame *real_display_frame = display_get_frame(disp.get());
173 memcpy(real_display_frame->tiles[0].data, frame->tiles[0].data, frame->tiles[0].data_len);
174 display_put_frame(disp.get(), real_display_frame, PUTF_BLOCKING);
175 }
176
177 vf_free(frame);
178 }
179}
180
190{
191 auto *s = (state_multiplier *) state;
192
193 assert(!s->displays.empty());
194
195 for (size_t i = 1; i < s->displays.size(); i++) {
196 display_run_new_thread(s->displays[i].get());
197 }
198
199 s->worker_thread = thread(display_multiplier_worker, state);
200
201 display_run_mainloop(s->displays[0].get());
202
203 s->worker_thread.join();
204 for (size_t i = 1; i < s->displays.size(); i++) {
205 display_join(s->displays[i].get());
206 }
207}
208
210{
211 auto *s = (state_multiplier *) state;
212 delete s;
213}
214
216{
217 auto *s = (state_multiplier *) state;
218
219 return vf_alloc_desc_data(s->desc);
220}
221
222static bool display_multiplier_putf(void *state, struct video_frame *frame, long long flags)
223{
224 auto *s = (state_multiplier *) state;
225
226 if (flags == PUTF_DISCARD) {
227 vf_free(frame);
228 } else {
229 unique_lock<mutex> lg(s->lock);
230 if (s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN) {
231 fprintf(stderr, "Multiplier: queue full!\n");
232 }
233 if (flags != PUTF_BLOCKING && s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN) {
234 vf_free(frame);
235 return false;
236 }
237 s->in_queue_decremented_cv.wait(lg, [s]{return s->incoming_queue.size() < IN_QUEUE_MAX_BUFFER_LEN;});
238 s->incoming_queue.push(frame);
239 lg.unlock();
240 s->cv.notify_one();
241 }
242
243 return true;
244}
245
246static bool display_multiplier_get_property(void *state, int property, void *val, size_t *len)
247{
248 auto *s = (state_multiplier *) state;
249
250 //TODO Find common properties, for now just return properties of the first display
251 return display_ctl_property(s->displays[0].get(), property, val, len);
252}
253
255{
256 auto *s = (state_multiplier *) state;
257
258 s->desc = desc;
259
260 for (auto &disp : s->displays) {
262 }
263
264 return true;
265}
266
268{
269 auto *s = static_cast<struct state_multiplier*>(state);
270
271 display_put_audio_frame(s->displays.at(0).get(), frame);
272}
273
275 int sample_rate)
276{
277 auto *s = static_cast<struct state_multiplier *>(state);
278
279 return display_reconfigure_audio(s->displays.at(0).get(), quant_samples, channels, sample_rate);
280}
281
282static void display_multiplier_probe(struct device_info **available_cards, int *count, void (**deleter)(void *)) {
284 *available_cards = nullptr;
285 *count = 0;
286}
287
301
#define UNUSED(x)
void ** state
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
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.
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define LOG(level)
Definition debug.h:313
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
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.
void display_run_mainloop(struct display *d)
Display mainloop function.
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 PUTF_DISCARD
#define PUTF_BLOCKING
#define VIDEO_DISPLAY_ABI_VERSION
#define DISPLAY_NO_GENERIC_FPS_INDICATOR
bool display_needs_mainloop(struct display *d)
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.
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_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
static constexpr unsigned int IN_QUEUE_MAX_BUFFER_LEN
static void display_multiplier_put_audio_frame(void *state, const struct audio_frame *frame)
static void display_multiplier_worker(void *state)
static void display_multiplier_done(void *state)
static void * display_multiplier_init(struct module *parent, const char *fmt, unsigned int flags)
static bool display_multiplier_reconfigure_audio(void *state, int quant_samples, int channels, int sample_rate)
static bool display_multiplier_get_property(void *state, int property, void *val, size_t *len)
static bool display_multiplier_reconfigure(void *state, struct video_desc desc)
static void display_multiplier_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
static constexpr int SKIP_FIRST_N_FRAMES_IN_STREAM
static void show_help()
static void check_reconf(struct state_multiplier *s, struct video_desc *current_desc, struct video_desc desc)
static const struct video_display_info display_multiplier_info
static void display_multiplier_run(void *state)
static constexpr const char * MOD_NAME
static bool display_multiplier_putf(void *state, struct video_frame *frame, long long flags)
static struct video_frame * display_multiplier_getf(void *state)
const char * parent
Definition settings.cpp:198
std::string_view tokenize(std::string_view &str, char delim, char quot)
Tokenizer for string_view.
struct used to comunicate with audio capture/playback device
Definition types.h:99
This struct represents initialized video display state.
std::vector< unique_disp > displays
queue< struct video_frame * > incoming_queue
condition_variable cv
struct video_desc desc
condition_variable in_queue_decremented_cv
struct module * parent
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
@ VIDEO_NORMAL
normal video (one tile)
Definition types.h:356
This is an umbrella header for video functions.
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.