#include #include #include #include #include #include #include "config_unix.h" #include "config_win32.h" #include "libug.h" #include "debug.h" #include "host.h" #include "src/host.h" #include "utils/wait_obj.h" #include "video.h" #include "video_display.h" #include "video_display/pipe.hpp" #include "video_rxtx.h" using namespace std; static char app_name[] = "(undefined)"; static char *argv[] = { app_name , nullptr }; static int argc = 1; extern "C" void exit_uv(int status); void exit_uv(int status) { should_exit = true; LOG(LOG_LEVEL_WARNING) << "Requested exit with code " << status << ".\n"; } static_assert(static_cast(UG_RGBA) == static_cast(RGBA)); static_assert(static_cast(UG_I420) == static_cast(I420)); static_assert(static_cast(UG_CUDA_RGBA) == static_cast(CUDA_RGBA)); //////////////////////////////////// // SENDER //////////////////////////////////// struct ug_sender { struct video_rxtx *video_rxtx{}; struct wait_obj *wait_obj = wait_obj_init(); struct module root_module; struct init_data *common; ug_sender() { common = common_preinit(argc, argv, nullptr); module_init_default(&root_module); root_module.cls = MODULE_CLASS_ROOT; //root_module.new_message = state_uv::new_message; root_module.priv_data = this; } ~ug_sender() { wait_obj_done(wait_obj); if (video_rxtx != nullptr) { video_rxtx->join(); delete video_rxtx; } common_cleanup(common); } }; struct ug_sender *ug_sender_init(const struct ug_sender_parameters *init_params) { assert(init_params != nullptr); if (init_params->receiver == nullptr) { LOG(LOG_LEVEL_ERROR) << "Receiver must be set!\n"; return nullptr; } log_level += init_params->verbose; struct ug_sender *s = new ug_sender(); chrono::steady_clock::time_point start_time(chrono::steady_clock::now()); map params; // common params["parent"].ptr = &s->root_module; params["exporter"].ptr = NULL; params["compression"].str = init_params->compression == UG_UNCOMPRESSED ? "none" : "libavcodec:codec=mjpeg"; params["rxtx_mode"].i = MODE_SENDER; params["paused"].b = false; //RTP params["mtu"].i = init_params->mtu != 0 ? init_params->mtu : 1500; params["receiver"].str = init_params->receiver; params["rx_port"].i = init_params->rx_port != 0 ? init_params->rx_port : DEFAULT_UG_PORT; params["tx_port"].i = init_params->tx_port != 0 ? init_params->tx_port : DEFAULT_UG_PORT; params["force_ip_version"].i = 0; params["mcast_if"].str = NULL; params["fec"].str = "none"; params["encryption"].str = NULL; params["bitrate"].ll = RATE_UNLIMITED; params["start_time"].cptr = (const void *) &start_time; params["video_delay"].vptr = 0; // UltraGrid RTP params["decoder_mode"].l = VIDEO_NORMAL; params["display_device"].ptr = NULL; params["shm_state"].ptr = nullptr; try { s->video_rxtx = video_rxtx::create("ultragrid_rtp", params); if (!s->video_rxtx) { delete s; return nullptr; } } catch (exception const &err) { cerr << err.what() << endl; delete s; return nullptr; } render_packet_received_callback = init_params->rprc; render_packet_received_callback_udata = init_params->rprc_udata; return s; } void ug_send_frame(struct ug_sender *s, const char *data, libug_pixfmt_t codec, int width, int height, uint32_t seq) { struct video_frame *f = vf_alloc(1); f->color_spec = (codec_t) codec; f->tiles[0].width = width; f->tiles[0].height = height; f->fps = 120; f->interlacing = PROGRESSIVE; f->id = seq; f->tiles[0].data = const_cast(data); f->tiles[0].data_len = vc_get_datalen(width, height, f->color_spec); wait_obj_reset(s->wait_obj); auto frame = shared_ptr(f, [&](struct video_frame *) { wait_obj_notify(s->wait_obj); }); s->video_rxtx->send(move(frame)); wait_obj_wait(s->wait_obj); vf_free(f); } void ug_sender_done(struct ug_sender *s) { render_packet_received_callback = nullptr; render_packet_received_callback_udata = nullptr; delete s; } //////////////////////////////////// // RECEIVER //////////////////////////////////// struct ug_receiver { struct video_rxtx *video_rxtx{}; struct display *display{}; struct module root_module; struct init_data *common; ug_receiver() { common = common_preinit(argc, argv, nullptr); module_init_default(&root_module); root_module.cls = MODULE_CLASS_ROOT; //root_module.new_message = state_uv::new_message; root_module.priv_data = this; } virtual ~ug_receiver() { if (video_rxtx != nullptr) { video_rxtx->join(); delete video_rxtx; } if (display != nullptr) { display_done(display); } common_cleanup(common); } pthread_t display_thread; pthread_t receiver_thread; }; struct ug_receiver *ug_receiver_start(struct ug_receiver_parameters *init_params) { struct ug_receiver *s = new ug_receiver(); chrono::steady_clock::time_point start_time(chrono::steady_clock::now()); map params; log_level += init_params->verbose; // common params["parent"].ptr = &s->root_module; params["exporter"].ptr = NULL; params["compression"].str = "none"; params["rxtx_mode"].i = MODE_RECEIVER; params["paused"].b = false; //RTP params["mtu"].i = 9000; // doesn't matter params["receiver"].str = init_params->sender ? init_params->sender : "localhost"; params["rx_port"].i = init_params->rx_port ? init_params->rx_port : DEFAULT_UG_PORT; params["tx_port"].i = init_params->tx_port ? init_params->tx_port : 0; params["force_ip_version"].i = 0; params["mcast_if"].str = NULL; params["fec"].str = "none"; params["encryption"].str = NULL; params["bitrate"].ll = RATE_UNLIMITED; params["start_time"].cptr = (const void *) &start_time; params["video_delay"].vptr = 0; char display[128] = "vrg"; const char *display_cfg = ""; if (init_params->display != nullptr) { strncpy(display, init_params->display, sizeof display); if (strchr(display, ':') != nullptr) { display_cfg = strchr(display, ':') + 1; *strchr(display, ':') = '\0'; } } if (init_params->decompress_to != 0) { commandline_params["decoder-use-codec"] = get_codec_name((codec_t) init_params->decompress_to); } if (init_params->force_gpu_decoding) { commandline_params["decompress"] = "gpujpeg"; } if (initialize_video_display(&s->root_module, display, display_cfg, 0, nullptr, &s->display) != 0) { LOG(LOG_LEVEL_ERROR) << "Unable to initialize VRG display!\n"; delete s; return nullptr; } // UltraGrid RTP params["decoder_mode"].l = VIDEO_NORMAL; params["display_device"].ptr = s->display; params["shm_state"].ptr = nullptr; try { s->video_rxtx = video_rxtx::create("ultragrid_rtp", params); if (s->video_rxtx == nullptr) { delete s; return nullptr; } } catch (exception const &err) { LOG(LOG_LEVEL_ERROR) << err.what() << endl; delete s; return nullptr; } pthread_create(&s->receiver_thread, NULL, video_rxtx::receiver_thread, (void *) s->video_rxtx); pthread_create(&s->display_thread, nullptr, (void* (*)(void*))(void *) display_run, s->display); return s; } void ug_receiver_done(struct ug_receiver *s) { exit_uv(0); pthread_join(s->receiver_thread, NULL); pthread_join(s->display_thread, NULL); delete s; }