UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
ultragrid_rtp.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2013-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
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#include "config_unix.h"
42#include "config_win32.h"
43#endif // HAVE_CONFIG_H
44
45#include "debug.h"
46
47#include <sstream>
48#include <string>
49#include <stdexcept>
50
51#include "control_socket.h"
52#include "export.h"
53#include "host.h"
54#include "lib_common.h"
55#include "messaging.h"
56#include "module.h"
57#include "pdb.h"
58#include "rtp/ldgm.h"
59#include "rtp/rtp.h"
60#include "rtp/rtp_callback.h"
61#include "rtp/video_decoders.h"
62#include "rtp/pbuf.h"
63#include "tfrc.h"
64#include "transmit.h"
65#include "tv.h"
66#include "utils/thread.h"
67#include "utils/vf_split.h"
68#include "video.h"
69#include "video_compress.h"
70#include "video_decompress.h"
71#include "video_display.h"
72#include "video_rxtx.hpp"
74#include "ug_runtime_error.hpp"
75#include "utils/worker.h"
76
77#include <chrono>
78#include <sstream>
79#include <utility>
80
81using namespace std;
82
84 rtp_video_rxtx(params), m_send_bytes_total(0)
85{
86 m_decoder_mode = (enum video_mode) params.at("decoder_mode").l;
87 m_display_device = (struct display *) params.at("display_device").ptr;
88 m_async_sending = false;
89
90 if (get_commandline_param("decoder-use-codec") != nullptr && "help"s == get_commandline_param("decoder-use-codec")) {
92 throw ug_no_error();
93 }
94
96 get_root_module(m_common.parent), "control");
97}
98
105
107{
109 unique_lock<mutex> lk(m_async_sending_lock);
110 m_async_sending_cv.wait(lk, [this]{return !m_async_sending;});
111}
112
114 ultragrid_rtp_video_rxtx *s = static_cast<ultragrid_rtp_video_rxtx *>(arg);
115 return s->receiver_loop();
116}
117
118void *(*ultragrid_rtp_video_rxtx::get_receiver_thread() noexcept)(void *arg)
119{
120 return receiver_thread;
121}
122
123void
124ultragrid_rtp_video_rxtx::send_frame(shared_ptr<video_frame> tx_frame) noexcept
125{
126 m_video_desc = video_desc_from_frame(tx_frame.get());
127 if (m_fec_state) {
128 tx_frame = m_fec_state->encode(tx_frame);
129 }
130
131 auto data = new pair<ultragrid_rtp_video_rxtx *, shared_ptr<video_frame>>(this, tx_frame);
132
133 unique_lock<mutex> lk(m_async_sending_lock);
134 m_async_sending_cv.wait(lk, [this]{return !m_async_sending;});
135 m_async_sending = true;
137 (void *) data);
138}
139
141 auto data = (pair<ultragrid_rtp_video_rxtx *, shared_ptr<video_frame>> *) arg;
142
143 data->first->send_frame_async(data->second);
144 delete data;
145
146 return NULL;
147}
148
149
150void ultragrid_rtp_video_rxtx::send_frame_async(shared_ptr<video_frame> tx_frame)
151{
152 lock_guard<mutex> lock(m_network_devices_lock);
153
154 tx_send(m_tx, tx_frame.get(), m_network_device);
155
156 if ((m_rxtx_mode & MODE_RECEIVER) == 0) { // otherwise receiver thread does the stuff...
157 time_ns_t curr_time = get_time_in_ns();
158 uint32_t ts = (curr_time - m_common.start_time) / 100'000 * 9; // at 90000 Hz
159 rtp_update(m_network_device, curr_time);
160 rtp_send_ctrl(m_network_device, ts, nullptr, curr_time);
161
162 // receive RTCP
163 bool ret = true;
164 do {
165 struct timeval timeout { 0, 0 };
166 ret = rtcp_recv_r(m_network_device, &timeout, ts);
167 } while (!m_should_exit && ret);
168 }
169
171 m_async_sending = false;
172 m_async_sending_lock.unlock();
173 m_async_sending_cv.notify_all();
174}
175
177{
178 struct msg_receiver *msg;
179 while ((msg = (struct msg_receiver *) check_message(&m_receiver_mod))) {
180 lock_guard<mutex> lock(m_network_devices_lock);
181 struct response *r = NULL;
182
183 switch (msg->type) {
185 {
186 assert(m_rxtx_mode == MODE_RECEIVER); // receiver only
187 auto *old_device = m_network_device;
188 auto old_port = m_recv_port_number;
189 m_recv_port_number = msg->new_rx_port;
195 m_common.ttl);
196 if (m_network_device == nullptr) {
197 log_msg(LOG_LEVEL_ERROR, "[control] Failed to change RX port to %d\n", msg->new_rx_port);
198 r = new_response(RESPONSE_INT_SERV_ERR, "Changing RX port failed!");
199 m_network_device = old_device;
200 m_recv_port_number = old_port;
201 } else {
202 log_msg(LOG_LEVEL_NOTICE, "[control] Changed RX port to %d\n", msg->new_rx_port);
203 destroy_rtp_device(old_device);
204 }
205 break;
206 }
208 {
209 pdb_iter_t it;
211 struct pdb_e *cp = pdb_iter_init(m_participants, &it);
212 while (cp) {
214 1.0 / msg->new_desc.fps);
215
216 cp = pdb_iter_next(&it);
217 }
218 }
219 break;
220 default:
221 assert(0 && "Wrong message passed to ultragrid_rtp_video_rxtx::receiver_process_messages()");
222 }
223
224 free_message((struct message *) msg, r ? r : new_response(RESPONSE_OK, NULL));
225 }
226}
227
233 if (m_participants != NULL) {
234 pdb_iter_t it;
235 struct pdb_e *cp = pdb_iter_init(m_participants, &it);
236 while (cp != NULL) {
237 if(cp->decoder_state)
239 ((struct vcodec_state*) cp->decoder_state)->decoder);
240 cp = pdb_iter_next(&it);
241 }
242 pdb_iter_done(&it);
243 }
244}
245
247 struct vcodec_state *video_decoder_state = (struct vcodec_state *) state;
248
249 if(!video_decoder_state) {
250 return;
251 }
252
253 video_decoder_destroy(video_decoder_state->decoder);
254
255 free(video_decoder_state);
256}
257
259 struct vcodec_state *state = (struct vcodec_state *) calloc(1, sizeof(struct vcodec_state));
260
261 if(state) {
264
265 if(!state->decoder) {
266 fprintf(stderr, "Error initializing decoder (incorrect '-M' or '-p' option?).\n");
267 free(state);
268 exit_uv(1);
269 return NULL;
270 } else {
271 //decoder_register_display(state->decoder, uv->display_device);
272 }
273 }
274
275 return state;
276}
277
279{
280 set_thread_name(__func__);
281 struct pdb_e *cp;
282 int fr;
283 int last_buf_size = rtp_get_recv_buf(m_network_device);
284
285#ifdef SHARED_DECODER
286 struct vcodec_state *shared_decoder = new_video_decoder(m_display_device);
287 if(shared_decoder == NULL) {
288 fprintf(stderr, "Unable to create decoder!\n");
289 exit_uv(1);
290 return NULL;
291 }
292#endif // SHARED_DECODER
293
294 fr = 1;
295
296 time_ns_t last_not_timeout = 0;
297
298 while (!m_should_exit) {
299 struct timeval timeout;
300 /* Housekeeping and RTCP... */
301 time_ns_t curr_time = get_time_in_ns();
302 uint32_t ts = (m_common.start_time - curr_time) / 100'000 * 9; // at 90000 Hz
303
304 rtp_update(m_network_device, curr_time);
305 rtp_send_ctrl(m_network_device, ts, nullptr, curr_time);
306
307 /* Receive packets from the network... The timeout is adjusted */
308 /* to match the video capture rate, so the transmitter works. */
309 if (fr) {
310 curr_time = get_time_in_ns();
312 fr = 0;
313 }
314
315 timeout.tv_sec = 0;
316 //timeout.tv_usec = 999999 / 59.94;
317 // use longer timeout when we are not receivng any data
318 if ((curr_time - last_not_timeout) > NS_IN_SEC) {
319 timeout.tv_usec = 100000;
320 } else {
321 timeout.tv_usec = 1000;
322 }
323 const bool ret = rtp_recv_r(m_network_device, &timeout, ts);
324
325 // timeout
326 if (!ret) {
327 // processing is needed here in case we are not receiving any data
329 //printf("Failed to receive data\n");
330 } else {
331 last_not_timeout = curr_time;
332 }
333
334 /* Decode and render for each participant in the conference... */
335 pdb_iter_t it;
336 cp = pdb_iter_init(m_participants, &it);
337 while (cp != NULL) {
338 if (tfrc_feedback_is_due(cp->tfrc_state, curr_time)) {
339 debug_msg("tfrc rate %f\n",
341 curr_time));
342 }
343
344 if(cp->decoder_state == NULL &&
345 !pbuf_is_empty(cp->playout_buffer)) { // the second check is needed because we want to assign display to participant that really sends data
346#ifdef SHARED_DECODER
347 cp->decoder_state = shared_decoder;
348#else
349 // we are assigning our display so we make sure it is removed from other dispaly
350
351 struct multi_sources_supp_info supp_for_mult_sources;
352 size_t len = sizeof(multi_sources_supp_info);
354 DISPLAY_PROPERTY_SUPPORTS_MULTI_SOURCES, &supp_for_mult_sources, &len);
355 if (!ret) {
356 supp_for_mult_sources.val = false;
357 }
358
359 struct display *d;
360 if (supp_for_mult_sources.val == false) {
361 remove_display_from_decoders(); // must be called before creating new decoder state
363 } else {
364 d = supp_for_mult_sources.fork_display(supp_for_mult_sources.state);
365 assert(d != NULL);
366 m_display_copies.push_back(d);
367 }
368
371
372 if (cp->decoder_state == NULL) {
373 log_msg(LOG_LEVEL_FATAL, "Fatal: unable to create decoder state for "
374 "participant %u.\n", cp->ssrc);
375 exit_uv(1);
376 break;
377 }
378#endif // SHARED_DECODER
379 }
380
381 struct vcodec_state *vdecoder_state = (struct vcodec_state *) cp->decoder_state;
382
383 /* Decode and render video... */
384 if (pbuf_decode
385 (cp->playout_buffer, curr_time, decode_video_frame, vdecoder_state)) {
386 fr = 1;
387 }
388
389 if(vdecoder_state && vdecoder_state->decoded % 100 == 99) {
390 int new_size = vdecoder_state->max_frame_size * 110ull / 100;
391 if(new_size > last_buf_size) {
392 if (rtp_set_recv_buf(m_network_device, new_size)) {
393 debug_msg("Recv buffer adjusted to %d\n", new_size);
394 } else {
396 }
397 last_buf_size = new_size;
398 }
399 }
400
401 pbuf_remove(cp->playout_buffer, curr_time);
402 cp = pdb_iter_next(&it);
403 }
404 pdb_iter_done(&it);
405 }
406
407#ifdef SHARED_DECODER
408 destroy_video_decoder(shared_decoder);
409#else
410 /* Because decoders work asynchronously we need to make sure
411 * that display won't be called */
413#endif // SHARED_DECODER
414
415 // pass posioned pill to display
417
418 return 0;
419}
420
425
426static video_rxtx *create_video_rxtx_ultragrid_rtp(std::map<std::string, param_u> const &params)
427{
429}
430
432 "UltraGrid RTP",
434};
435
437
void ** state
int void size_t * len
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
std::mutex m_network_devices_lock
Definition rtp.hpp:72
static struct rtp * initialize_network(const char *addrs, int recv_port_base, int send_port_base, struct pdb *participants, int force_ip_version, const char *mcast_if, int ttl)
Definition rtp.cpp:267
int m_recv_port_number
Definition rtp.hpp:76
struct rtp * m_network_device
Definition rtp.hpp:71
static void destroy_rtp_device(struct rtp *network_devices)
Definition rtp.cpp:305
struct pdb * m_participants
Definition rtp.hpp:74
std::string m_requested_receiver
Definition rtp.hpp:75
int m_send_port_number
Definition rtp.hpp:77
static void display_buf_increase_warning(int size)
Definition rtp.cpp:241
struct tx * m_tx
Definition rtp.hpp:73
static void * send_frame_async_callback(void *arg)
struct display * m_display_device
virtual void send_frame_async(std::shared_ptr< video_frame >)
std::list< struct display * > m_display_copies
struct vcodec_state * new_video_decoder(struct display *d)
virtual void send_frame(std::shared_ptr< video_frame >) noexcept override
virtual void *(*)(void *arg) get_receiver_thread() noexcept
struct control_state * m_control
std::condition_variable m_async_sending_cv
enum video_mode m_decoder_mode
static void destroy_video_decoder(void *state)
ultragrid_rtp_video_rxtx(std::map< std::string, param_u > const &)
static void * receiver_thread(void *arg)
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 debug_msg(...)
#define debug_msg(...) log_msg(LOG_LEVEL_DEBUG, "[pid/%d +%d %s] ", getpid(), LINE,...
Definition debug.h:92
#define LOG_LEVEL_FATAL
errors that prevent UG run
Definition debug.h:58
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.
#define PUTF_BLOCKING
void display_done(struct display *d)
This function performs cleanup after done.
@ DISPLAY_PROPERTY_SUPPORTS_MULTI_SOURCES
struct module * get_module(struct module *root, const char *const_path)
Definition module.c:264
struct module * get_root_module(struct module *node)
Definition module.c:203
void video_decoder_destroy(struct state_video_decoder *decoder)
Destroys decoder created with decoder_init()
void video_decoder_remove_display(struct state_video_decoder *decoder)
This removes display from current decoder.
int decode_video_frame(struct coded_data *cdata, void *decoder_data, struct pbuf_stats *stats)
Decodes a participant buffer representing one video frame.
void exit_uv(int status)
Definition host.cpp:625
const char * get_commandline_param(const char *key)
Definition host.cpp:894
#define MODE_RECEIVER
Definition host.h:103
@ LIBRARY_CLASS_VIDEO_RXTX
Definition lib_common.h:84
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
void free_message(struct message *msg, struct response *r)
struct response * new_response(int status, const char *text)
struct message * check_message(struct module *mod)
#define RESPONSE_OK
Definition messaging.h:57
@ RECEIVER_MSG_CHANGE_RX_PORT
Definition messaging.h:109
@ RECEIVER_MSG_VIDEO_PROP_CHANGED
Definition messaging.h:110
#define RESPONSE_INT_SERV_ERR
Definition messaging.h:63
int pbuf_decode(struct pbuf *playout_buf, time_ns_t curr_time, decode_frame_t decode_func, void *data)
Definition pbuf.c:562
void pbuf_set_playout_delay(struct pbuf *playout_buf, double playout_delay)
Definition pbuf.c:597
int pbuf_is_empty(struct pbuf *playout_buf)
Definition pbuf.c:553
void pbuf_remove(struct pbuf *playout_buf, time_ns_t curr_time)
Definition pbuf.c:498
void pdb_iter_done(pdb_iter_t *it)
Definition pdb.c:412
struct pdb_e * pdb_iter_next(pdb_iter_t *it)
Definition pdb.c:402
struct pdb_e * pdb_iter_init(struct pdb *db, pdb_iter_t *it)
Definition pdb.c:393
void * pdb_iter_t
Definition pdb.h:106
bool rtp_set_recv_buf(struct rtp *session, int bufsize)
Definition rtp.c:3938
void rtp_update(struct rtp *session, time_ns_t curr_time)
Definition rtp.c:3456
uint32_t rtp_my_ssrc(struct rtp *session)
Definition rtp.c:1401
void rtp_send_ctrl(struct rtp *session, uint32_t rtp_ts, rtcp_app_callback appcallback, time_ns_t curr_time)
Definition rtp.c:3409
int rtp_get_recv_buf(struct rtp *session)
Definition rtp.c:3944
bool rtp_recv_r(struct rtp *session, struct timeval *timeout, uint32_t curr_rtp_ts)
Receive RTP packets and dispatch them.
Definition rtp.c:2338
bool rtcp_recv_r(struct rtp *session, struct timeval *timeout, uint32_t curr_rtp_ts)
Definition rtp.c:2398
struct msghdr msg
char encryption[STR_LEN]
Definition host.h:172
int ttl
Definition host.h:175
char mcast_if[STR_LEN]
Definition host.h:173
struct module * parent
Definition host.h:171
time_ns_t start_time
Definition host.h:178
int force_ip_version
Definition host.h:176
This struct represents initialized video display state.
struct display *(* fork_display)(void *state)
Definition pdb.h:72
decoder_state_deleter_t decoder_state_deleter
decoder state deleter
Definition pdb.h:82
struct tfrc * tfrc_state
Definition pdb.h:85
void * decoder_state
state of decoder for participant
Definition pdb.h:81
uint32_t ssrc
Definition pdb.h:73
struct pbuf * playout_buffer
Definition pdb.h:84
unsigned int decoded
Definition pbuf.h:95
unsigned int max_frame_size
Definition pbuf.h:93
struct state_video_decoder * decoder
Definition pbuf.h:92
bool m_should_exit
struct module m_receiver_mod
virtual void join()
struct common_opts m_common
double tfrc_feedback_txrate(struct tfrc *state, time_ns_t curr_time)
Definition tfrc.c:486
uint32_t ts
Definition tfrc.c:101
int tfrc_feedback_is_due(struct tfrc *state, time_ns_t curr_time)
Definition tfrc.c:474
void set_thread_name(const char *name)
Definition thread.c:72
void tx_send(struct tx *tx, struct video_frame *frame, struct rtp *rtp_session)
Definition transmit.cpp:407
long long time_ns_t
Definition tv.h:81
#define NS_IN_SEC
Definition tv.h:92
static time_ns_t get_time_in_ns()
Definition tv.h:101
video_mode
Definition types.h:354
static video_rxtx * create_video_rxtx_ultragrid_rtp(std::map< std::string, param_u > const &params)
static const struct video_rxtx_info ultragrid_rtp_video_rxtx_info
This is an umbrella header for video functions.
API for video compress drivers.
struct state_video_decoder * video_decoder_init(struct module *parent, enum video_mode video_mode, struct display *display, const char *encryption)
Initializes video decompress state.
Video RTP decoder.
API for video decompress drivers.
#define VIDEO_RXTX_ABI_VERSION
void task_run_async_detached(runnable_t task, void *data)
Runs task asynchronously in a detached state.
Definition worker.cpp:275