UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
display.c
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 */
42#ifdef HAVE_CONFIG_H
43#include "config.h"
44#include "config_unix.h"
45#include "config_win32.h"
46#endif /* HAVE_CONFIG_H */
47
48#include "capture_filter.h"
49#include "compat/strings.h" // strdupa
50#include "debug.h"
51#include "lib_common.h"
52#include "utils/color_out.h"
53#include "utils/list.h"
54#include "utils/text.h"
55#include "video.h"
56#include "video_codec.h"
57#include "video_display.h"
58#include "video_frame.h"
59
60#define MAX_QUEUE_LEN 3
61#define MOD_NAME "[display cap. f.] "
62
63struct module;
64
65static int init(struct module *parent, const char *cfg, void **state);
66static void done(void *state);
67static struct video_frame *filter(void *state, struct video_frame *in);
68
70 struct display *d;
71
73
74 pthread_mutex_t lock;
75 pthread_cond_t cv;
76 pthread_t thread_id;
77};
78
79static codec_t select_display_codec(codec_t *display_codecs, codec_t recv_codec) {
80 if (codec_is_in_set(recv_codec, display_codecs)) {
81 return recv_codec;
82 }
84 get_best_decoder_from(recv_codec, display_codecs, &out);
85 return out;
86}
87
88static void *worker(void *arg) {
89 struct capture_filter_display *s = arg;
90 struct video_desc configured_desc = { 0 };
91 codec_t display_codecs[VIDEO_CODEC_COUNT + 1];
92 size_t len = sizeof display_codecs;
93 if (!display_ctl_property(s->d, DISPLAY_PROPERTY_CODECS, display_codecs, &len)) {
94 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Cannot query display supported codecs!\n");
95 exit_uv(1);
96 return NULL;
97 }
98 display_codecs[len / sizeof display_codecs[0]] = VIDEO_CODEC_NONE;
99 int rgb_shift[] = { DEFAULT_R_SHIFT, DEFAULT_G_SHIFT, DEFAULT_B_SHIFT };
100 len = sizeof rgb_shift;
101 if (!display_ctl_property(s->d, DISPLAY_PROPERTY_RGB_SHIFT, rgb_shift, &len)) {
102 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Cannot query display RGB shift!\n");
103 }
104 decoder_t dec = NULL;
105 int src_linesize = 0;
106 int dst_linesize = 0;
107
108 while (1) {
109 pthread_mutex_lock(&s->lock);
110 while (simple_linked_list_size(s->frame_queue) == 0) {
111 pthread_cond_wait(&s->cv, &s->lock);
112 }
114 pthread_mutex_unlock(&s->lock);
115 if (!f) {
116 display_put_frame(s->d, NULL, PUTF_BLOCKING); // pass poison pill
117 break;
118 }
119
120 struct video_desc new_desc = video_desc_from_frame(f);
121 if (!video_desc_eq(configured_desc, new_desc)) {
122 struct video_desc display_desc = new_desc;
123 display_desc.color_spec = select_display_codec(display_codecs, new_desc.color_spec);
124 if (!display_desc.color_spec || !display_reconfigure(s->d, display_desc, VIDEO_NORMAL)) {
125 log_msg(LOG_LEVEL_ERROR, "Unable to reconfigure to %s!\n", video_desc_to_string(display_desc));
126 continue;
127 }
128 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Reconfigured display to %s\n", video_desc_to_string(display_desc));
129 dec = get_decoder_from_to(new_desc.color_spec, display_desc.color_spec);
130 src_linesize = vc_get_linesize(f->tiles[0].width, f->color_spec);
131 dst_linesize = vc_get_linesize(f->tiles[0].width, display_desc.color_spec);
132 configured_desc = new_desc;
133 }
134 struct video_frame *df = display_get_frame(s->d);
135 for (size_t i = 0; i < f->tiles[0].height; ++i) {
136 dec((unsigned char *) df->tiles[0].data + i * dst_linesize, (unsigned char *) f->tiles[0].data + i * src_linesize, dst_linesize, rgb_shift[0], rgb_shift[1], rgb_shift[2]);
137 }
139 vf_free(f);
140 }
141
142 return NULL;
143}
144
145static int init(struct module *parent, const char *cfg, void **state)
146{
147 char warn[] = MOD_NAME "Capture filter \"display\" is experimental and may not "
148 "always work as expected, especially if the same SW display "
149 "type (eg. GL) is given as both preview display and a regular one.";
151
152 if (strlen(cfg) == 0 || strcmp(cfg, "help") == 0) {
153 color_printf("Previews captured frame with specified dispay.\n"
154 "Usage:\n"
155 "\t" TBOLD("--capture-filter display:<display_cfg>") "\n");
156 return 1;
157 }
158
159 char *requested_display = strdupa(cfg);
160 char *delim = strchr(requested_display, ':');
161 const char *fmt = "";
162 if (delim) {
163 *delim = '\0';
164 fmt = delim + 1;
165 }
166 struct display *d;
167 int ret = initialize_video_display(parent, requested_display,
168 fmt, 0, NULL, &d);
169 if (ret != 0) {
170 return ret;
171 }
172
173 struct capture_filter_display *s = calloc(1, sizeof *s);
174 s->d = d;
176 pthread_mutex_init(&s->lock, NULL);
177 pthread_cond_init(&s->cv, NULL);
178
180 pthread_create(&s->thread_id, NULL, worker, s);
181
182 *state = s;
183 return 0;
184}
185
186static struct video_frame *filter(void *state, struct video_frame *in)
187{
188 struct capture_filter_display *s = state;
189 struct video_frame *f = in ? vf_get_copy(in) : NULL;
190 pthread_mutex_lock(&s->lock);
192 pthread_mutex_unlock(&s->lock);
193 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Queue full, frame not displayed.\n");
194 vf_free(f);
195 return in;
196 }
198 pthread_mutex_unlock(&s->lock);
199 pthread_cond_signal(&s->cv);
200
201 return in;
202}
203
204static void done(void *state)
205{
206 struct capture_filter_display *s = state;
207 filter(s, NULL);
208 pthread_join(s->thread_id, NULL);
209 display_join(s->d);
210 display_done(s->d);
211 pthread_mutex_destroy(&s->lock);
212 pthread_cond_destroy(&s->cv);
214 free(s);
215}
216
218 .init = init,
219 .done = done,
220 .filter = filter,
221};
222
224
void ** state
const char * fmt
int void size_t * len
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.
int vc_get_linesize(unsigned int width, codec_t codec)
#define CAPTURE_FILTER_ABI_VERSION
int color_printf(const char *format,...)
#define TBOLD(x)
Definition color_out.h:70
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
static struct video_frame * filter(void *state, struct video_frame *in)
Definition display.c:186
#define MAX_QUEUE_LEN
Definition display.c:60
static void * worker(void *arg)
Definition display.c:88
#define MOD_NAME
Definition display.c:61
static codec_t select_display_codec(codec_t *display_codecs, codec_t recv_codec)
Definition display.c:79
static void done(void *state)
Definition display.c:204
static int init(struct module *parent, const char *cfg, void **state)
Definition display.c:145
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.
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_BLOCKING
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_RGB_SHIFT
red,green,blue shift - int[3] (bits)
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
void exit_uv(int status)
Definition host.cpp:625
@ LIBRARY_CLASS_CAPTURE_FILTER
Definition lib_common.h:75
#define REGISTER_HIDDEN_MODULE(name, info, lclass, abi)
Definition lib_common.h:156
void simple_linked_list_append(struct simple_linked_list *l, void *data)
Definition list.cpp:68
int simple_linked_list_size(struct simple_linked_list *l)
Definition list.cpp:93
struct simple_linked_list * simple_linked_list_init(void)
Definition list.cpp:53
void simple_linked_list_destroy(struct simple_linked_list *l)
Definition list.cpp:58
void * simple_linked_list_pop(struct simple_linked_list *l)
Definition list.cpp:82
decoder_t get_decoder_from_to(codec_t in, codec_t out)
decoder_t get_best_decoder_from(codec_t in, const codec_t *out_candidates, codec_t *out)
#define DEFAULT_B_SHIFT
Definition pixfmt_conv.h:72
#define DEFAULT_R_SHIFT
Definition pixfmt_conv.h:70
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
#define DEFAULT_G_SHIFT
Definition pixfmt_conv.h:71
const char * parent
Definition settings.cpp:198
#define strdupa(s)
Definition strings.h:77
struct display * d
Definition display.c:70
struct simple_linked_list * frame_queue
Definition display.c:72
pthread_mutex_t lock
Definition display.c:74
pthread_t thread_id
Definition display.c:76
pthread_cond_t cv
Definition display.c:75
This struct represents initialized video display state.
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int height
Definition types.h:281
codec_t color_spec
Definition types.h:182
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
codec_t color_spec
Definition types.h:306
@ VIDEO_NORMAL
normal video (one tile)
Definition types.h:356
codec_t
Definition types.h:65
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ VIDEO_CODEC_COUNT
count of known video codecs (including VIDEO_CODEC_NONE)
Definition types.h:108
char * wrap_paragraph(char *text)
Definition text.c:204
const char * video_desc_to_string(struct video_desc d)
Definition video.cpp:241
This is an umbrella header for video functions.
bool codec_is_in_set(codec_t codec, const codec_t *set)
bool display_reconfigure(struct display *d, struct video_desc desc, enum video_mode video_mode)
Reconfigure display to new video format.
struct video_frame * vf_get_copy(struct video_frame *original_frame)
Makes deep copy of the video frame.
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.