UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
unix_sock.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2022-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#include "config.h"
39#include "config_unix.h"
40#include "config_win32.h"
41#include "debug.h"
42#include "lib_common.h"
43
44#include <condition_variable>
45#include <list>
46#include <map>
47#include <vector>
48#include <memory>
49#include <mutex>
50#include <queue>
51#include <cmath>
52#include <iostream>
53#include <thread>
54
55#include "host.h"
56#include "video.h"
57#include "video_display.h"
58#include "video_codec.h"
59#include "utils/fs.h"
60#include "utils/misc.h"
61#include "utils/macros.h"
62#include "utils/color_out.h"
64#include "tools/ipc_frame.h"
65#include "tools/ipc_frame_ug.h"
67
68#define MOD_NAME "[unix sock disp] "
69
70#define DEFAULT_PREVIEW_FILENAME "ug_preview_disp_unix"
71#define DEFAULT_DISP_FILENAME "ug_unix"
72
73#define DEFAULT_SCALE_W 960
74#define DEFAULT_SCALE_H 540
75
76using ipc_frame_conv_func_t = bool (*)(struct Ipc_frame *dst,
77 const struct video_frame *src,
79 unsigned scale_factor);
80
81static constexpr unsigned int IN_QUEUE_MAX_BUFFER_LEN = 5;
82static constexpr int SKIP_FIRST_N_FRAMES_IN_STREAM = 5;
83
84static void display_unix_sock_run(void *state);
85
86namespace{
87struct frame_deleter { void operator()(video_frame *f){ vf_free(f); } };
88using unique_frame = std::unique_ptr<video_frame, frame_deleter>;
89}
90
92 std::queue<unique_frame> incoming_queue;
93 std::condition_variable frame_consumed_cv;
94 std::condition_variable frame_available_cv;
95 std::mutex lock;
96
99
102
103 int target_width = -1;
105
107
109
110 struct module *parent;
111 std::thread thread_id;
112};
113
114static void show_help(){
115 col() << "unix_socket/preview display. The two display are identical apart from their defaults and the fact that preview never blocks on putf().\n";
116 col() << "usage:\n";
117 col() << TBOLD(TRED("\t-d (unix_socket|preview)") << "[:path=<path>][:target_size=<w>x<h>]")
118 << "\n\n";
119 col() << "options:\n";
120 col() << TBOLD("\tpath=<path>") << "\tpath to unix socket to connect to. Defaults are \""
121 << get_temp_dir() << DEFAULT_PREVIEW_FILENAME "\" for preview and \""
122 << get_temp_dir() << DEFAULT_DISP_FILENAME "\" for unix_sock\n";
123 col() << TBOLD("\ttarget_size=<w>x<h>")<< "\tScales the video frame so that the total number of pixel is around <w>x<h>. If -1x-1 is passed, no scaling takes place."
124 << "Defaults are -1x-1 for unix_sock and " TOSTRING(DEFAULT_SCALE_W) "x" TOSTRING(DEFAULT_SCALE_H) " for preview.\n";
125 col() << TBOLD("\thq") << "\tUse higher quality downscale\n";
126}
127
129 const char *fmt,
130 unsigned int flags,
131 bool is_preview)
132{
133 UNUSED(flags);
134 UNUSED(fmt);
135
136 auto s = std::make_unique<state_unix_sock>();
137
138 std::string_view fmt_sv = fmt ? fmt : "";
139
140 std::string socket_path = get_temp_dir();
141 socket_path += DEFAULT_DISP_FILENAME;
142
143 if(is_preview){
144 socket_path = get_temp_dir();
145 socket_path += DEFAULT_PREVIEW_FILENAME;
146 s->target_width = DEFAULT_SCALE_W;
147 s->target_height = DEFAULT_SCALE_H;
148 s->ignore_putf_blocking = true;
149 }
150
151 while(!fmt_sv.empty()){
152 auto tok = tokenize(fmt_sv, ':', '"');
153 auto key = tokenize(tok, '=');
154
155 if(key == "help"){
156 show_help();
157 return INIT_NOERR;
158 } else if(key == "path"){
159 socket_path = tokenize(tok, '=');
160 } else if(key == "key"){
161 socket_path += tokenize(tok, '=');
162 } else if(key == "hq"){
163 s->ipc_conv = ipc_frame_from_ug_frame_hq;
164 } else if(key == "target_size"){
165 auto val = tokenize(tok, '=');
166 if(!parse_num(tokenize(val, 'x'), s->target_width)
167 || !parse_num(tokenize(val, 'x'), s->target_height))
168 {
169 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Failed to parse resolution\n");
170 return nullptr;
171 }
172 }
173 }
174
175 s->parent = parent;
176 s->ipc_frame.reset(ipc_frame_new());
177 s->frame_writer.reset(ipc_frame_writer_new(socket_path.c_str()));
178 if(!s->frame_writer){
179 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Unable to init ipc writer for path %s\n", socket_path.c_str());
180 return nullptr;
181 }
182
183 s->thread_id = std::thread(display_unix_sock_run, s.get());
184 return s.release();
185}
186
187static void display_unix_sock_run(void *state)
188{
189 auto s = static_cast<state_unix_sock *>(state);
190 int skipped = 0;
191
192 while (1) {
193 auto frame = [&]{
194 std::unique_lock<std::mutex> l(s->lock);
195 s->frame_available_cv.wait(l,
196 [s]{return s->incoming_queue.size() > 0;});
197 auto frame = std::move(s->incoming_queue.front());
198 s->incoming_queue.pop();
199 s->frame_consumed_cv.notify_one();
200 return frame;
201 }();
202
203 if (!frame) {
204 break;
205 }
206
207 if (skipped < SKIP_FIRST_N_FRAMES_IN_STREAM){
208 skipped++;
209 continue;
210 }
211
212 const tile *tile = &frame->tiles[0];
213
215 s->target_width, s->target_height);
216
217 if(!s->ipc_conv(s->ipc_frame.get(), frame.get(),
218 RGB, scale))
219 {
220 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Unable to convert\n");
221 continue;
222 }
223
224 errno = 0;
225 if(!ipc_frame_writer_write(s->frame_writer.get(), s->ipc_frame.get())){
226 perror(MOD_NAME "Unable to send frame");
227 continue;
228 }
229 }
230}
231
233{
234 auto s = static_cast<state_unix_sock *>(state);
235 s->thread_id.join();
236
237 delete s;
238}
239
241{
242 auto s = static_cast<state_unix_sock *>(state);
243
244 return vf_alloc_desc_data(s->desc);
245}
246
247static bool display_unix_sock_putf(void *state, struct video_frame *frame, long long flags)
248{
249 auto s = static_cast<state_unix_sock *>(state);
250 auto f = unique_frame(frame);
251
252 if (flags == PUTF_DISCARD)
253 return true;
254
255 std::unique_lock<std::mutex> lg(s->lock);
256 if (s->incoming_queue.size() >= IN_QUEUE_MAX_BUFFER_LEN){
257 if(flags != PUTF_BLOCKING){
258 log_msg(LOG_LEVEL_WARNING, MOD_NAME "queue full!\n");
259 return false;
260 }
261 if(s->ignore_putf_blocking){
262 return false;
263 }
264 }
265
266 s->frame_consumed_cv.wait(lg, [s]{return s->incoming_queue.size() < IN_QUEUE_MAX_BUFFER_LEN;});
267 s->incoming_queue.push(std::move(f));
268 lg.unlock();
269 s->frame_available_cv.notify_one();
270
271 return true;
272}
273
274static bool display_unix_sock_get_property(void *state, int property, void *val, size_t *len)
275{
276 UNUSED(state);
277 codec_t codecs[] = {UYVY, RGBA, RGB};
278 enum interlacing_t supported_il_modes[] = {PROGRESSIVE, INTERLACED_MERGED, SEGMENTED_FRAME};
279 int rgb_shift[] = {0, 8, 16};
280
281 switch (property) {
283 if(sizeof(codecs) <= *len) {
284 memcpy(val, codecs, sizeof(codecs));
285 } else {
286 return false;
287 }
288
289 *len = sizeof(codecs);
290 break;
292 if(sizeof(rgb_shift) > *len) {
293 return false;
294 }
295 memcpy(val, rgb_shift, sizeof(rgb_shift));
296 *len = sizeof(rgb_shift);
297 break;
299 *(int *) val = PITCH_DEFAULT;
300 *len = sizeof(int);
301 break;
303 if(sizeof(supported_il_modes) <= *len) {
304 memcpy(val, supported_il_modes, sizeof(supported_il_modes));
305 } else {
306 return false;
307 }
308 *len = sizeof(supported_il_modes);
309 break;
310 default:
311 return false;
312 }
313 return true;
314}
315
317{
318 auto s = static_cast<state_unix_sock *>(state);
319
320 s->desc = desc;
321
322 return true;
323}
324
326{
327 UNUSED(state);
328 UNUSED(frame);
329}
330
332 int sample_rate)
333{
334 UNUSED(state);
338
339 return false;
340}
341
342static void display_unix_sock_probe(struct device_info **available_cards, int *count, void (**deleter)(void *)) {
344 *available_cards = nullptr;
345 *count = 0;
346}
347
348static void *display_unix_sock_init_preview(struct module *parent, const char *fmt, unsigned int flags) {
349 return display_unix_sock_init(parent, fmt, flags, true);
350}
351
352static void *display_unix_sock_init_no_preview(struct module *parent, const char *fmt, unsigned int flags) {
353 return display_unix_sock_init(parent, fmt, flags, false);
354}
355
369
383
385
387
#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_frame * vf_alloc_desc_data(struct video_desc desc)
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
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
#define PITCH_DEFAULT
default pitch, i. e. respective linesize
#define PUTF_DISCARD
#define PUTF_BLOCKING
#define VIDEO_DISPLAY_ABI_VERSION
@ 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_SUPPORTED_IL_MODES
display supported interlacing modes - enum interlacing_t[]
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
int count
Definition hd-rum.c:44
#define INIT_NOERR
Definition host.h:73
Ipc_frame * ipc_frame_new()
Definition ipc_frame.cpp:48
std::unique_ptr< Ipc_frame, Ipc_frame_deleter > Ipc_frame_uniq
Definition ipc_frame.h:40
bool ipc_frame_from_ug_frame_hq(struct Ipc_frame *dst, const struct video_frame *src, codec_t codec, unsigned scale_factor)
Same as ipc_frame_from_ug_frame, but convert pixfmt first and scale later.
bool ipc_frame_from_ug_frame(struct Ipc_frame *dst, const struct video_frame *src, codec_t codec, unsigned scale_factor)
Make an ipc frame from ultragrid frame.
int ipc_frame_get_scale_factor(int src_w, int src_h, int target_w, int target_h)
bool ipc_frame_writer_write(struct Ipc_frame_writer *writer, const struct Ipc_frame *f)
Ipc_frame_writer * ipc_frame_writer_new(const char *path)
std::unique_ptr< Ipc_frame_writer, Ipc_frame_writer_deleter > Ipc_frame_writer_uniq
@ LIBRARY_CLASS_VIDEO_DISPLAY
Definition lib_common.h:79
#define REGISTER_HIDDEN_MODULE(name, info, lclass, abi)
Definition lib_common.h:156
#define TOSTRING(A)
Definition macros.h:49
bool(*)(struct Ipc_frame *dst, const struct video_frame *src, codec_t codec, unsigned scale_factor) ipc_frame_conv_func_t
Definition preview.cpp:80
static const char * get_temp_dir(void)
const char * parent
Definition settings.cpp:198
std::string_view tokenize(std::string_view &str, char delim, char quot)
Tokenizer for string_view.
bool parse_num(std::string_view sv, T &res, int base=10)
struct used to comunicate with audio capture/playback device
Definition types.h:99
void operator()(video_frame *f)
Definition pipewire.cpp:77
struct module * parent
struct video_desc desc
Definition unix_sock.cpp:97
ipc_frame_conv_func_t ipc_conv
std::thread thread_id
std::condition_variable frame_available_cv
Definition unix_sock.cpp:94
Ipc_frame_writer_uniq frame_writer
struct video_desc display_desc
Definition unix_sock.cpp:98
std::condition_variable frame_consumed_cv
Definition unix_sock.cpp:93
bool ignore_putf_blocking
std::queue< unique_frame > incoming_queue
Definition unix_sock.cpp:92
Ipc_frame_uniq ipc_frame
std::mutex lock
Definition unix_sock.cpp:95
Struct tile is an area of video_frame.
Definition types.h:279
unsigned int width
Definition types.h:280
unsigned int height
Definition types.h:281
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
interlacing_t
Definition types.h:163
@ PROGRESSIVE
progressive frame
Definition types.h:164
@ SEGMENTED_FRAME
Segmented frame. Contains the same data as progressive frame.
Definition types.h:168
@ INTERLACED_MERGED
Columngs of both fields are interlaced together.
Definition types.h:167
codec_t
Definition types.h:65
@ 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
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
static bool display_unix_sock_reconfigure_audio(void *state, int quant_samples, int channels, int sample_rate)
static void * display_unix_sock_init_preview(struct module *parent, const char *fmt, unsigned int flags)
static constexpr unsigned int IN_QUEUE_MAX_BUFFER_LEN
Definition unix_sock.cpp:81
static void display_unix_sock_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
#define DEFAULT_SCALE_H
Definition unix_sock.cpp:74
static void display_unix_sock_done(void *state)
static bool display_unix_sock_reconfigure(void *state, struct video_desc desc)
bool(*)(struct Ipc_frame *dst, const struct video_frame *src, codec_t codec, unsigned scale_factor) ipc_frame_conv_func_t
Definition unix_sock.cpp:76
static const struct video_display_info display_preview_info
static constexpr int SKIP_FIRST_N_FRAMES_IN_STREAM
Definition unix_sock.cpp:82
#define DEFAULT_PREVIEW_FILENAME
Definition unix_sock.cpp:70
static void show_help()
static void display_unix_sock_run(void *state)
static bool display_unix_sock_putf(void *state, struct video_frame *frame, long long flags)
static bool display_unix_sock_get_property(void *state, int property, void *val, size_t *len)
#define MOD_NAME
Definition unix_sock.cpp:68
static struct video_frame * display_unix_sock_getf(void *state)
static void display_unix_sock_put_audio_frame(void *state, const struct audio_frame *frame)
#define DEFAULT_SCALE_W
Definition unix_sock.cpp:73
static void * display_unix_sock_init_no_preview(struct module *parent, const char *fmt, unsigned int flags)
#define DEFAULT_DISP_FILENAME
Definition unix_sock.cpp:71
static void * display_unix_sock_init(struct module *parent, const char *fmt, unsigned int flags, bool is_preview)
static const struct video_display_info display_unix_sock_info
This is an umbrella header for video functions.
std::unique_ptr< video_frame, frame_deleter > unique_frame
Definition pipewire.cpp:78
const char * key
Definition cineform.cpp:125
static struct @76 codecs[]