UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
spout.cpp File Reference
#include <array>
#include <cctype>
#include <chrono>
#include <iostream>
#include <memory>
#include <SpoutLibrary.h>
#include <synchapi.h>
#include <string>
#include "debug.h"
#include "gl_context.h"
#include "host.h"
#include "lib_common.h"
#include "spout_sender.h"
#include "utils/color_out.h"
#include "utils/text.h"
#include "video.h"
#include "video_capture.h"
Include dependency graph for spout.cpp:

Go to the source code of this file.

Classes

struct  state_vidcap_spout
 

Macros

#define DEFAULT_CODEC   RGB
 
#define DEFAULT_FPS   60.0
 
#define MOD_NAME   "[spout cap.] "
 

Functions

 REGISTER_MODULE (spout, &vidcap_spout_info, LIBRARY_CLASS_VIDEO_CAPTURE, VIDEO_CAPTURE_ABI_VERSION)
 
static void usage ()
 
static void vidcap_spout_done (void *state)
 
static struct video_frame * vidcap_spout_grab (void *state, struct audio_frame **audio)
 
static int vidcap_spout_init (struct vidcap_params *params, void **state)
 
static void vidcap_spout_probe (device_info **available_cards, int *count, void(**deleter)(void *))
 

Variables

static const struct video_capture_info vidcap_spout_info
 

Detailed Description

Author
Martin Pulec pulec.nosp@m.@ces.nosp@m.net.c.nosp@m.z

Definition in file spout.cpp.

Macro Definition Documentation

◆ DEFAULT_CODEC

#define DEFAULT_CODEC   RGB

Definition at line 59 of file spout.cpp.

Referenced by usage(), and vidcap_spout_init().

◆ DEFAULT_FPS

#define DEFAULT_FPS   60.0

Definition at line 58 of file spout.cpp.

Referenced by usage(), and vidcap_spout_init().

◆ MOD_NAME

#define MOD_NAME   "[spout cap.] "

Definition at line 61 of file spout.cpp.

Referenced by vidcap_spout_init(), and vidcap_spout_probe().

Function Documentation

◆ REGISTER_MODULE()

REGISTER_MODULE ( spout ,
& vidcap_spout_info,
LIBRARY_CLASS_VIDEO_CAPTURE ,
VIDEO_CAPTURE_ABI_VERSION  )

◆ usage()

static void usage ( void )
static

Definition at line 84 of file spout.cpp.

85{
86 col() << "Usage:\n";
87 col() << "\t" << TBOLD(TRED("-t spout") << "[:name=<server_name>][:fps=<fps>][:codec=<codec>]") << "\n";
88 col() << "where\n";
89 col() << "\t" << TBOLD("name") << "\n\t\tSpout server name\n";
90 col() << "\t" << TBOLD("fps") << "\n\t\tFPS count (default: " << DEFAULT_FPS << ")\n";
91 col() << "\t" << TBOLD("codec") << "\n\t\tvideo codec (default: " << get_codec_name(DEFAULT_CODEC) << ")\n";
92 col() << "\nServers:\n";
93 auto receiver = shared_ptr<SPOUTLIBRARY>(GetSpout(), [](auto s) {s->Release();});
94 int count = receiver->GetSenderCount();
95
96 for (int i = 0; i < count; ++i) {
97 array<char, 256> name{};
98 if (!receiver->GetSender(i, name.data(), name.size())) {
99 LOG(LOG_LEVEL_ERROR) << "Cannot get name for server #" << i << "\n";
100 continue;
101 }
102 unsigned int width = 0;
103 unsigned int height = 0;
104 HANDLE dxShareHandle = 0;
105 DWORD dwFormat = 0;
106 if (!receiver->GetSenderInfo(name.data(), width, height, dxShareHandle, dwFormat)) {
107 LOG(LOG_LEVEL_ERROR) << "Cannot get server " << name.data() << "details\n";
108 }
109 col() << "\t" << TBOLD(<< name.data() <<) << ") width: " << width << ", height: " << height << "\n";
110 }
111}
const char * get_codec_name(codec_t codec)
#define TRED(x)
Definition color_out.h:75
#define TBOLD(x)
Definition color_out.h:70
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG(level)
Definition debug.h:313
int count
Definition hd-rum.c:44
const char * name
Definition settings.cpp:193
#define DEFAULT_CODEC
Definition spout.cpp:59
#define DEFAULT_FPS
Definition spout.cpp:58

References count, DEFAULT_CODEC, DEFAULT_FPS, get_codec_name(), LOG, LOG_LEVEL_ERROR, name, TBOLD, and TRED.

Referenced by vidcap_spout_init().

Here is the call graph for this function:

◆ vidcap_spout_done()

static void vidcap_spout_done ( void * state)
static

Definition at line 199 of file spout.cpp.

200{
202
204 s->spout_state->ReleaseReceiver();
206
207 delete s;
208}
void ** state
void destroy_gl_context(struct gl_context *context)
Definition gl_context.c:223
void gl_context_make_current(struct gl_context *context)
Definition gl_context.c:236
struct gl_context glc
Definition spout.cpp:75
shared_ptr< SPOUTLIBRARY > spout_state
Definition spout.cpp:74

References destroy_gl_context(), gl_context_make_current(), state_vidcap_spout::glc, state_vidcap_spout::spout_state, and state.

Here is the call graph for this function:

◆ vidcap_spout_grab()

static struct video_frame * vidcap_spout_grab ( void * state,
struct audio_frame ** audio )
static

Definition at line 210 of file spout.cpp.

211{
212 enum {
213 MS100 = 100,
214 };
216
218 struct video_frame *out = vf_alloc_desc_data(s->desc);
220
221 bool ret = s->spout_state->ReceiveImage((unsigned char *) out->tiles[0].data, s->gl_format);
222 if (!ret) {
223 vf_free(out);
225 MSG(WARNING, "No signal detected...\n");
226 Sleep(MS100);
227 return NULL;
228 }
229 if (s->spout_state->IsUpdated()) {
230 s->desc.width = s->spout_state->GetSenderWidth();
231 s->desc.height = s->spout_state->GetSenderHeight();
232 MSG(NOTICE,
233 "Server updated - name: %s, size: %dx%d, fps: "
234 "%g, codec: %s\n",
235 s->spout_state->GetSenderName(), s->desc.width,
236 s->desc.height, s->desc.fps,
238 vf_free(out);
240 return NULL;
241 }
243
244 // wait until this frame is due
245 decltype(s->last_frame_captured) t;
246 do {
247 t = std::chrono::steady_clock::now();
248 } while (std::chrono::duration_cast<std::chrono::duration<double>>(t - s->last_frame_captured).count() < 1 / out->fps);
249 s->last_frame_captured = t;
250
251 *audio = NULL;
252 return out;
253}
struct audio_frame ** audio
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
#define MSG(l, fmt,...)
Definition debug.h:96
struct video_desc desc
Definition spout.cpp:73
std::chrono::steady_clock::time_point last_frame_captured
Definition spout.cpp:80
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
codec_t color_spec
Definition types.h:182
double fps
Definition types.h:183
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
void(* dispose)(struct video_frame *)
Definition types.h:245
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
double fps
Definition types.h:308
struct video_frame_callbacks callbacks
Definition types.h:324

References audio, video_frame::callbacks, video_desc::color_spec, tile::data, state_vidcap_spout::desc, video_frame_callbacks::dispose, video_desc::fps, video_frame::fps, get_codec_name(), gl_context_make_current(), state_vidcap_spout::gl_format, state_vidcap_spout::glc, video_desc::height, state_vidcap_spout::last_frame_captured, MSG, state_vidcap_spout::spout_state, state, video_frame::tiles, vf_alloc_desc_data(), vf_free(), and video_desc::width.

Here is the call graph for this function:

◆ vidcap_spout_init()

static int vidcap_spout_init ( struct vidcap_params * params,
void ** state )
static

Definition at line 113 of file spout.cpp.

114{
117 }
118
120
121 double fps = DEFAULT_FPS;
123
124 char *opts = strdup(vidcap_params_get_fmt(params));
125 char *item, *save_ptr;
126 int ret = VIDCAP_INIT_OK;
127
128 item = strtok_r(opts, ":", &save_ptr);
129 while (item) {
130 if (strcmp(item, "help") == 0) {
131 usage();
132 ret = VIDCAP_INIT_NOERR;
133 break;
134 } else if (strstr(item, "name=") == item) {
135 char *name = item + strlen("name=");
136 if (strstr(name, "urlencoded=") == name) {
137 name += strlen("urlencoded=");
138 if (urldecode(s->server_name, sizeof s->server_name, name) == 0) {
139 LOG(LOG_LEVEL_WARNING) << MOD_NAME << "Improperly formatted name: " << item + strlen("name=") << "\n";
140 ret = VIDCAP_INIT_FAIL;
141 }
142 } else {
143 strncpy(s->server_name, item + strlen("name="), sizeof(s->server_name) - 1);
144 }
145 } else if (strstr(item, "fps=") == item) {
146 fps = atof(item + strlen("fps="));
147 } else if (strstr(item, "codec=") == item) {
148 codec = get_codec_from_name(item + strlen("codec="));
149 } else {
150 LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Unknown argument - " << item << "\n";
151 ret = VIDCAP_INIT_FAIL;
152 break;
153 }
154 item = strtok_r(NULL, ":", &save_ptr);
155 }
156
157 free(opts);
158
159 if (ret != VIDCAP_INIT_OK) {
160 delete s;
161 return ret;
162 }
163
164 switch (codec) {
165 case RGB:
166 s->gl_format = GL_RGB;
167 break;
168 case RGBA:
169 s->gl_format = GL_RGBA;
170 break;
171 default:
172 LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Unsupported codec: " << get_codec_name(codec) << "! Currently only RGB and RGBA are supported.\n";
173 delete s;
174 return VIDCAP_INIT_FAIL;
175 }
176
177
179 LOG(LOG_LEVEL_ERROR) << MOD_NAME << "Unable to initialize GL context!\n";
180 delete s;
181 return VIDCAP_INIT_FAIL;
182 }
184
185 s->spout_state = shared_ptr<SPOUTLIBRARY>(GetSpout(), [](auto s) {s->Release();});
187 if (strlen(s->server_name) != 0) {
188 s->spout_state->SetReceiverName(s->server_name);
189 }
190
192 s->desc = video_desc{0, 0, codec, fps, PROGRESSIVE, 1};
193
194 MSG(INFO, "initialized successfully, waiting for input...\n");
195 *state = s;
196 return VIDCAP_INIT_OK;
197}
codec_t get_codec_from_name(const char *name)
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
bool init_gl_context(struct gl_context *context, int which)
initializes specified OpenGL context
Definition gl_context.c:69
#define GL_CONTEXT_ANY
Definition gl_context.h:72
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_INIT_FAIL
error ocured
#define VIDCAP_INIT_AUDIO_NOT_SUPPORTED
card does not support audio
volatile int log_level
Definition debug.cpp:65
static void usage()
Definition spout.cpp:84
#define MOD_NAME
Definition spout.cpp:61
void spout_set_log_level(void *s, int ug_level)
Definition hd-rum.c:27
char server_name[256]
Definition spout.cpp:78
@ PROGRESSIVE
progressive frame
Definition types.h:164
codec_t
Definition types.h:65
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
size_t urldecode(char *out, size_t max_len, const char *in)
Definition text.c:129
const char * vidcap_params_get_fmt(const struct vidcap_params *params)
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY

References DEFAULT_CODEC, DEFAULT_FPS, state_vidcap_spout::desc, get_codec_from_name(), get_codec_name(), GL_CONTEXT_ANY, gl_context_make_current(), state_vidcap_spout::gl_format, state_vidcap_spout::glc, init_gl_context(), LOG, log_level, LOG_LEVEL_ERROR, LOG_LEVEL_WARNING, MOD_NAME, MSG, name, PROGRESSIVE, RGB, RGBA, state_vidcap_spout::server_name, spout_set_log_level(), state_vidcap_spout::spout_state, state, urldecode(), usage(), VIDCAP_FLAG_AUDIO_ANY, VIDCAP_INIT_AUDIO_NOT_SUPPORTED, VIDCAP_INIT_FAIL, VIDCAP_INIT_NOERR, VIDCAP_INIT_OK, vidcap_params_get_flags(), and vidcap_params_get_fmt().

Here is the call graph for this function:

◆ vidcap_spout_probe()

static void vidcap_spout_probe ( device_info ** available_cards,
int * count,
void(** deleter )(void *) )
static

Definition at line 255 of file spout.cpp.

256{
257 *deleter = free;
258 *count = 0;
259
260 auto receiver = shared_ptr<SPOUTLIBRARY>(GetSpout(), [](auto s) {s->Release();});
261
262 int sender_count = receiver->GetSenderCount();
263
264 *available_cards = (struct device_info *) calloc(sender_count, sizeof(struct device_info));
265 if (*available_cards == nullptr) {
266 return;
267 }
268 *count = sender_count;
269
270 for (int i = 0; i < *count; ++i) {
271 array<char, 256> name{};
272 auto& card = (*available_cards)[i];
273 if (!receiver->GetSender(i, name.data(), name.size())) {
274 LOG(LOG_LEVEL_VERBOSE) << MOD_NAME << "Cannot get name for server #" << i << "\n";
275 snprintf(card.dev, sizeof card.dev, ":device=%d", i);
276 snprintf(card.name, sizeof card.name, "Spout #%d", i);
277 } else {
278 snprintf(card.dev, sizeof card.dev, ":name=urlencoded=");
279 urlencode(card.dev + strlen(card.dev),
280 sizeof card.dev - strlen(card.dev),
281 name.data(), urlencode_rfc3986_eval, false);
282 snprintf(card.name, sizeof card.name, "Spout %s", name.data());
283 }
284 card.repeatable = true;
285 }
286}
int void(** deleter)(void *))
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
int urlencode_rfc3986_eval(int c)
Definition text.c:59
size_t urlencode(char *out, size_t max_len, const char *in, int(*eval_pass)(int c), bool space_plus_replace)
Definition text.c:81

References count, deleter, LOG, LOG_LEVEL_VERBOSE, MOD_NAME, name, urlencode(), and urlencode_rfc3986_eval().

Here is the call graph for this function:

Variable Documentation

◆ vidcap_spout_info

const struct video_capture_info vidcap_spout_info
static
Initial value:
= {
}
static int vidcap_spout_init(struct vidcap_params *params, void **state)
Definition spout.cpp:113
static void vidcap_spout_done(void *state)
Definition spout.cpp:199
static void vidcap_spout_probe(device_info **available_cards, int *count, void(**deleter)(void *))
Definition spout.cpp:255
static struct video_frame * vidcap_spout_grab(void *state, struct audio_frame **audio)
Definition spout.cpp:210

Definition at line 288 of file spout.cpp.